Overall Statistics |
Total Trades 228 Average Win 0.15% Average Loss -0.21% Compounding Annual Return 5.856% Drawdown 2.600% Expectancy 0.018 Net Profit 0.495% Sharpe Ratio 0.545 Probabilistic Sharpe Ratio 43.821% Loss Rate 40% Win Rate 60% Profit-Loss Ratio 0.71 Alpha 0 Beta 0 Annual Standard Deviation 0.081 Annual Variance 0.007 Information Ratio 0.545 Tracking Error 0.081 Treynor Ratio 0 Total Fees $556.07 Estimated Strategy Capacity $17000000.00 Lowest Capacity Asset AAPL R735QTJ8XC9X |
from AlgorithmImports import * class IntradayBreakout(QCAlgorithm): def Initialize(self): self.UniverseSettings.Resolution = Resolution.Second self.SetStartDate(2022, 3, 18) self.SetEndDate(2022, 4, 18) self.SetWarmUp(timedelta(days = 1)) self.SetCash(100000) self.SetTimeZone("America/New_York") self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) self.stopLossPercentLong = .998 self.stopLossPercentLong2 = .999 self.takeProfitPercentLong = 1.003 self.takeProfitPercentLong2 = 1.003 self.stopLossPercentShort = 1.005 self.stopLossPercentShort2 = 1.0015 self.takeProfitPercentShort = .996 self.takeProfitPercentShort2 = .995 self.timeCheck = False self.symbolData = {} tickers = ["AAPL"] #just one ticker for ease of debugging for ticker in tickers: symbol = self.AddEquity(ticker, Resolution.Second).Symbol self.symbolData[symbol] = SymbolData(self, symbol) everyday = self.DateRules.EveryDay(symbol) self.Schedule.On(everyday, self.TimeRules.BeforeMarketClose(symbol, 10), self.Liquidate) self.Schedule.On(everyday, self.TimeRules.BeforeMarketClose(symbol, 30), self.timeCheckNight) self.Schedule.On(everyday, self.TimeRules.AfterMarketOpen(symbol, 5), self.timeCheckMorning) def timeCheckMorning(self): self.timeCheck = True def timeCheckNight(self): self.timeCheck = False def OnEndOfDay(self): for data in self.symbolData.values(): data.longTrade = True data.shortTrade = True data.killswitch = False data.killswitch2 = False data.killswitch3 = False data.vwap.Reset() def OnData(self, slice): if not all([data.IsReady for data in self.symbolData.values()]): return for symbol, data in self.symbolData.items(): if slice.Bars.ContainsKey(symbol): data.window15sec.Add(slice.Bars[symbol]) #####self.Debug(f'{symbol} test') for symbol, data in self.symbolData.items(): price = self.Securities[symbol].Price stddeviationwindowlong = (3 * data.stdcalc.Current.Value) #when I debug, clearly the calculation is wrong, because it should take 15 seconds to recieve a new bar, but it updates more frequently than that, and sometimes returns 0.00 #self.Debug(f'{symbol} {stddeviationwindowlong} stdtest') if data.window15sec.IsReady: windowDelta = data.window15sec[0].Close - data.window15sec[14].Open # if I reverse the greater than operator, the algo will not place orders, presently, the algo places the same orders if lines 85-88 are commented out # I **want** it to place orders if the windowDelta is greater than 3* the std deviation of my 15 second ranges created in symbolData if windowDelta < stddeviationwindowlong: if data.rsi.Current.Value < 25: if data.vwap.Current.Value / price > 1.003: if data.longTrade: if self.timeCheck: marketorderticket = self.SetHoldings(symbol, 1.0) data.stopmarketorderticket = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.stopLossPercentLong) data.limitorderticket = self.LimitOrder(symbol, round(-self.Portfolio[symbol].Quantity / 2), price * self.takeProfitPercentLong) data.longTrade = False #worry about shorts later '''for symbol, data in self.symbolData.items(): price = self.Securities[symbol].Price stddeviationwindowshort = (-3 * data.stdcalc.Current.Value) if (data.smaVol15.Current.Value / data.smaVol390.Current.Value) > 2.0: if price < data.vwap.Current.Value: if data.window15min.IsReady: windowDelta = data.window15min[0].Close - data.window15min[4].Open if windowDelta < stddeviationwindowshort: if data.shortTrade: if self.timeCheck: marketorderticketshort = self.SetHoldings(symbol, -0.15) data.stopmarketorderticketshort = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.stopLossPercentShort) data.limitorderticketshort = self.LimitOrder(symbol, round(-self.Portfolio[symbol].Quantity / 2), price * self.takeProfitPercentShort) data.shortTrade = False''' def OnOrderEvent(self, orderEvent): data = self.symbolData.get(orderEvent.Symbol, None) if not data or orderEvent.Status != OrderStatus.Filled: return for symbol, data in self.symbolData.items(): price = self.Securities[symbol].Price if orderEvent.Status != OrderStatus.Filled: return if data.stopmarketorderticket != None and data.stopmarketorderticket.OrderId == orderEvent.OrderId: if data.killswitch2 == True: data.killswitch3 = True if data.stopmarketorderticket != None and data.stopmarketorderticket.OrderId == orderEvent.OrderId: if data.killswitch == True: data.killswitch2 = True if data.stopmarketorderticket != None and data.stopmarketorderticket.OrderId == orderEvent.OrderId: data.limitorderticket.Cancel() data.longTrade = True data.killswitch = True if data.limitorderticket != None and data.limitorderticket.OrderId == orderEvent.OrderId: data.stopmarketorderticket.Cancel() data.limitorderticket2 = self.LimitOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.takeProfitPercentLong2) data.stopmarketorderticket2 = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.stopLossPercentLong2) data.killswitch = False if data.limitorderticket2 != None and data.limitorderticket2.OrderId == orderEvent.OrderId: data.stopmarketorderticket2.Cancel() data.longTrade = True if data.stopmarketorderticket2 != None and data.stopmarketorderticket2.OrderId == orderEvent.OrderId: data.limitorderticket2.Cancel() data.longTrade = True if data.stopmarketorderticketshort != None and data.stopmarketorderticketshort.OrderId == orderEvent.OrderId: data.limitorderticketshort.Cancel() if data.limitorderticketshort != None and data.limitorderticketshort.OrderId == orderEvent.OrderId: data.stopmarketorderticketshort.Cancel() data.limitorderticketshort2 = self.LimitOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.takeProfitPercentShort2) data.stopmarketorderticketshort2 = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, price * self.stopLossPercentShort2) if data.limitorderticketshort2 != None and data.limitorderticketshort2.OrderId == orderEvent.OrderId: data.stopmarketorderticketshort2.Cancel() if data.stopmarketorderticketshort2 != None and data.stopmarketorderticketshort2.OrderId == orderEvent.OrderId: data.limitorderticketshort2.Cancel() class SymbolData: def __init__(self, algorithm, symbol): fifteensecConsolidator = TradeBarConsolidator(timedelta(seconds = 15)) self.subscribe = algorithm.SubscriptionManager.AddConsolidator(symbol, fifteensecConsolidator) self.consolidateddd = algorithm.Consolidate(symbol, timedelta(seconds = 15), self.fifteensecbarhandler) self.high = algorithm.SMA(symbol, 1, Resolution.Minute, Field.High) self.low = algorithm.SMA(symbol, 1, Resolution.Minute, Field.Low) self.RegisterIndicator = algorithm.RegisterIndicator(symbol, self.high, fifteensecConsolidator) self.RegisterIndicator = algorithm.RegisterIndicator(symbol, self.low, fifteensecConsolidator) self.range = IndicatorExtensions.Minus(self.high,self.low) period = 1560 #15sec x 4 = 1 min, 390 min in session self.std = StandardDeviation(period) # should calculate the std deviation of the range of the 15 second bars and return updated calculation every 15 seconds when a new bar arrives and the oldest is discarded self.stdcalc = IndicatorExtensions.Of(self.range,self.std) # window that updates every second, the idea is that at any point, the change in price over the most recent 15 seconds could be statistically outside of normal range self.window15sec = RollingWindow[TradeBar](15) self.vwap = algorithm.VWAP(symbol, 390, Resolution.Minute) self.rsi = algorithm.RSI(symbol, 20, Resolution.Minute) #one trade per security at a time self.longTrade = True self.shortTrade = True self.stopmarketorderticket = None self.stopmarketorderticket2 = None self.limitorderticket = None self.limitorderticket2 = None self.stopmarketorderticketshort = None self.stopmarketorderticketshort2 = None self.limitorderticketshort = None self.limitorderticketshort2 = None def fifteensecbarhandler(self, consolidated): pass @property def IsReady(self): return all ([stdcalc.IsReady for stdcalc in self.stdcalc.values()]) ([window15sec.IsReady for window15 in self.window15sec.values()])