Overall Statistics |
Total Trades 18 Average Win 0.26% Average Loss -0.13% Compounding Annual Return 14.132% Drawdown 0.500% Expectancy 0.332 Net Profit 0.387% Sharpe Ratio -2.11 Probabilistic Sharpe Ratio 27.918% Loss Rate 56% Win Rate 44% Profit-Loss Ratio 2.00 Alpha -0.023 Beta 0.062 Annual Standard Deviation 0.024 Annual Variance 0.001 Information Ratio 1.438 Tracking Error 0.267 Treynor Ratio -0.804 Total Fees $22.58 Estimated Strategy Capacity $31000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
#region imports from AlgorithmImports import * #endregion # Opening Range Breakout # ------------------------------------------------------------ STOCK = "SPY"; PERIOD = 30; WAIT = 0 # ; SL = -0.005; TP = 0.005; # ------------------------------------------------------------ class OpeningRangeBreakout(QCAlgorithm): def Initialize(self): self.SetStartDate(2022, 5, 10) self.SetEndDate(2022, 5, 20) self.SetCash(100000) self.stock = self.AddEquity(STOCK, Resolution.Minute).Symbol self.hh = self.MAX(self.stock, PERIOD, Resolution.Minute, Field.High) self.ll = self.MIN(self.stock, PERIOD, Resolution.Minute, Field.Low) # self.hh_d = IndicatorExtensions.Of(Delay(1), self.hh) # self.ll_d = IndicatorExtensions.Of(Delay(1), self.ll) self.SetWarmUp(PERIOD + 1, Resolution.Minute) self.first_30_min_HH = 0 self.first_30_min_LL = 0 self.trailingH = 0 self.trailingL = 0 self.stopMarketTicket = None self.stopMarketTicketShort = None self.wait = WAIT self.tradeLimit = True # Check if the data is warmed up and ready to trade self.Schedule.On(self.DateRules.EveryDay(self.stock), self.TimeRules.AfterMarketOpen(self.stock, 31), self.DailyCheck) # If stop loss is not hit, liquidate positions 5 mins before close self.Schedule.On(self.DateRules.EveryDay(self.stock), self.TimeRules.BeforeMarketClose(self.stock, 5), self.Liquidate) def DailyCheck(self): if self.IsWarmingUp: return # if not (self.hh_d.IsReady or self.ll_d.IsReady): return # self.first_30_min_HH = self.hh_d.Current.Value # self.first_30_min_LL = self.ll_d.Current.Value self.first_30_min_HH = self.hh.Current.Value self.first_30_min_LL = self.ll.Current.Value self.trailingH = self.first_30_min_HH self.trailingL = self.first_30_min_LL def OnData(self, data): if self.IsWarmingUp: return # if not (self.hh_d.IsReady or self.ll_d.IsReady): return if self.Time.hour < 10 or self.Time.hour >= 16: return if (self.first_30_min_HH ==0 or self.first_30_min_LL == 0): return self.wait += 1 if not self.wait > WAIT: return price = self.Securities[self.stock].Price # pnl = self.Securities[self.stock].Holdings.UnrealizedProfitPercent # If portfolio not invested, open a position if it breaks the opening range if not self.Portfolio[self.stock].Invested: if price > self.first_30_min_HH and self.tradeLimit == True: self.SetHoldings(self.stock, 1) self.stopMarketTicket = self.StopMarketOrder("SPY", -self.Portfolio["SPY"].Quantity, 0.9975 * price) self.tradeLimit = False elif price < self.first_30_min_LL and self.tradeLimit == True: self.SetHoldings(self.stock, -1) self.stopMarketTicketShort = self.StopMarketOrder("SPY", -self.Portfolio["SPY"].Quantity, 1.0025 * price) self.tradeLimit = False # If portfolio is invested, use a trailing stop elif self.Portfolio[self.stock].Invested: # if pnl >= TP: # self.Liquidate(self.stock, "Take Profit") # self.wait = 0 # elif pnl < SL: # self.Liquidate(self.stock, "Stop Loss") # self.wait = 0 if self.Securities["SPY"].High > self.trailingH: self.trailingH = self.Securities["SPY"].High updateFields = UpdateOrderFields() updateFields.StopPrice = self.trailingH * 0.9975 if self.stopMarketTicket != None: ### your update request was returning NoneType because of your conditional logic, attempting to update tickets that did not exist self.stopMarketTicket.Update(updateFields) elif self.Securities["SPY"].Low < self.trailingL: self.trailingL = self.Securities["SPY"].Low updateFields = UpdateOrderFields() updateFields.StopPrice = self.trailingL * 1.0025 if self.stopMarketTicketShort != None: ### your update request was returning NoneType because of your conditional logic, attempting to update tickets that did not exist self.stopMarketTicketShort.Update(updateFields) def OnEndOfDay(self, symbol): self.first_30_min_HH = 0 self.first_30_min_LL = 0 self.trailingH = 0 self.trailingL = 0 self.stopMarketTicket = None self.stopMarketTicketShort = None self.tradeLimit = True self.wait = WAIT