Overall Statistics |
Total Trades 10 Average Win 1.89% Average Loss -0.57% Compounding Annual Return 443.817% Drawdown 0.900% Expectancy 1.596 Net Profit 4.587% Sharpe Ratio 14.612 Probabilistic Sharpe Ratio 94.384% Loss Rate 40% Win Rate 60% Profit-Loss Ratio 3.33 Alpha 2.154 Beta -0.461 Annual Standard Deviation 0.175 Annual Variance 0.031 Information Ratio 7.208 Tracking Error 0.477 Treynor Ratio -5.55 Total Fees $11.94 Estimated Strategy Capacity $100000000.00 Lowest Capacity Asset SPY R735QTJ8XC9X |
class OpeningRangeBreakout(QCAlgorithm): openingBar = None def Initialize(self): self.SetStartDate(2022, 4, 20) self.SetEndDate(2022, 4, 30) self.SetCash(100000) self.stock = self.AddEquity("SPY", Resolution.Minute).Symbol self.max = self.MAX(self.stock, 30, Resolution.Minute) self.min = self.MIN(self.stock, 30, Resolution.Minute) self.SetWarmUp(timedelta(minutes=30)) self.stopMarketTicket = None self.stopMarketTicketShort = None self.highestSPYPrice = 0 # definitely higher than this self.lowestSPYPrice = 1000000 #almost certainly than this... self.spy30High = 0 self.spy30Low = 0 # at 10AM the new method is called to save down values self.Schedule.On(self.DateRules.EveryDay(self.stock), self.TimeRules.AfterMarketOpen(self.stock, 30), self.First30Values) self.Schedule.On(self.DateRules.EveryDay(self.stock), self.TimeRules.BeforeMarketClose(self.stock, 5), self.Liquidate) #saves value of indcators at 10 am def First30Values(self): self.spy30High = self.max.Current.Value self.spy30Low = self.min.Current.Value # resets the value for next day def OnEndOfDay(self): self.spy30High = 0 self.spy30Low = 0 self.stopMarketTicket = None self.stopMarketTicketShort = None def OnData(self, data): if self.IsWarmingUp: return if not (self.max.IsReady or self.min.IsReady): return if self.Time.hour < 10 or self.Time.hour > 10: return price = self.Securities[self.stock].Price if not self.Portfolio.Invested: if price > self.spy30High: self.SetHoldings("SPY", 1.0) self.stopMarketTicket = self.StopMarketOrder("SPY", -self.Portfolio["SPY"].Quantity, 0.995 * price) # self.limitOrderTicket = self.LimitOrder("SPY", -self.Portfolio["SPY"].Quantity, 1.01 * price) elif price < self.spy30Low: self.SetHoldings("SPY", -1.0) self.stopMarketTicketShort = self.StopMarketOrder("SPY", -self.Portfolio["SPY"].Quantity, 1.005 * price) # self.limitOrderTicketShort = self.LimitOrder("SPY", -self.Portfolio["SPY"].Quantity, .99 * price) if self.Securities["SPY"].High > self.highestSPYPrice: #2. Save the new high to highestSPYPrice; then update the stop price to 90% of highestSPYPrice self.highestSPYPrice = self.Securities[self.stock].High updateFields = UpdateOrderFields() updateFields.StopPrice = self.highestSPYPrice * 0.995 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) if self.Securities["SPY"].Low < self.lowestSPYPrice: #2. Save the new high to highestSPYPrice; then update the stop price to 90% of highestSPYPrice self.lowestSPYPrice = self.Securities[self.stock].Low updateFields = UpdateOrderFields() updateFields.StopPrice = self.lowestSPYPrice * 1.005 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 OnOrderEvent(self, orderEvent): if orderEvent.Status != OrderStatus.Filled: return if self.stopMarketTicket is not None and self.stopMarketTicket.OrderId == orderEvent.OrderId: self.stopMarketOrderFillTime = self.Time elif self.stopMarketTicketShort is not None and self.stopMarketTicketShort.OrderId == orderEvent.OrderId: self.stopMarketOrderShortFillTime = self.Time