|
| 1 | +#AI generated code extracted from Sapate, Uttam B, Trading Range Breakout Test on Daily Stocks of Indian Markets (November 10, 2017). |
| 2 | +#Available at SSRN: https://ssrn.com/abstract=3068852 or http://dx.doi.org/10.2139/ssrn.3068852 |
| 3 | + |
| 4 | +from AlgorithmImports import * |
| 5 | + |
| 6 | +class MyTradingAlgorithm(QCAlgorithm): |
| 7 | + def Initialize(self): |
| 8 | + # Set the start and end date for backtesting |
| 9 | + self.SetStartDate(2024, 1, 1) |
| 10 | + self.SetEndDate(2024, 12, 1) |
| 11 | + |
| 12 | + # Set the initial cash balance |
| 13 | + self.SetCash(100000) |
| 14 | + |
| 15 | + # Add the assets to trade |
| 16 | + self.symbols = [self.AddEquity("SPY", Resolution.Daily).Symbol, |
| 17 | + self.AddEquity("AAPL", Resolution.Daily).Symbol] |
| 18 | + |
| 19 | + # Set the benchmark |
| 20 | + self.SetBenchmark("SPY") |
| 21 | + |
| 22 | + # Initialize indicators |
| 23 | + self.sma_short = {symbol: self.SMA(symbol, 50, Resolution.Daily) for symbol in self.symbols} |
| 24 | + self.sma_long = {symbol: self.SMA(symbol, 200, Resolution.Daily) for symbol in self.symbols} |
| 25 | + |
| 26 | + # Initialize risk management parameters |
| 27 | + self.stop_loss_pct = 0.05 |
| 28 | + self.trailing_stop_pct = 0.02 |
| 29 | + |
| 30 | + # Initialize portfolio construction parameters |
| 31 | + self.max_position_size = 0.5 # Max 50% of portfolio in one position |
| 32 | + |
| 33 | + # Schedule the rebalancing function |
| 34 | + self.Schedule.On(self.DateRules.MonthStart(), self.TimeRules.AfterMarketOpen("SPY", 30), self.Rebalance) |
| 35 | + |
| 36 | + def OnData(self, data): |
| 37 | + for symbol in self.symbols: |
| 38 | + if not data.ContainsKey(symbol): |
| 39 | + continue |
| 40 | + |
| 41 | + # Check if indicators are ready |
| 42 | + if not self.sma_short[symbol].IsReady or not self.sma_long[symbol].IsReady: |
| 43 | + continue |
| 44 | + |
| 45 | + # Strategy logic: Golden Cross |
| 46 | + if self.sma_short[symbol].Current.Value > self.sma_long[symbol].Current.Value: |
| 47 | + self.SetHoldings(symbol, self.max_position_size) |
| 48 | + else: |
| 49 | + self.Liquidate(symbol) |
| 50 | + |
| 51 | + # Risk management: Trailing stop loss |
| 52 | + if self.Portfolio[symbol].Invested: |
| 53 | + self.SetTrailingStopLoss(symbol, self.trailing_stop_pct) |
| 54 | + |
| 55 | + def Rebalance(self): |
| 56 | + # Rebalance the portfolio |
| 57 | + for symbol in self.symbols: |
| 58 | + self.SetHoldings(symbol, self.max_position_size) |
| 59 | + |
| 60 | + def SetTrailingStopLoss(self, symbol, trailing_stop_pct): |
| 61 | + # Set a trailing stop loss for the given symbol |
| 62 | + if self.Portfolio[symbol].Invested: |
| 63 | + stop_price = self.Portfolio[symbol].Price * (1 - trailing_stop_pct) |
| 64 | + self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, stop_price) |
| 65 | + |
| 66 | + def OnOrderEvent(self, orderEvent): |
| 67 | + # Log order events for debugging |
| 68 | + self.Debug(f"Order event: {orderEvent}") |
| 69 | + |
| 70 | + def OnEndOfAlgorithm(self): |
| 71 | + # Log final portfolio value |
| 72 | + self.Debug(f"Final Portfolio Value: {self.Portfolio.TotalPortfolioValue}") |
| 73 | + |
| 74 | +# Helper functions can be added here if needed |
0 commit comments