Overall Statistics
Total Trades
1150
Average Win
0.55%
Average Loss
-0.42%
Compounding Annual Return
4.723%
Drawdown
14.500%
Expectancy
0.062
Net Profit
14.872%
Sharpe Ratio
0.508
Probabilistic Sharpe Ratio
13.831%
Loss Rate
54%
Win Rate
46%
Profit-Loss Ratio
1.31
Alpha
0.036
Beta
-0.014
Annual Standard Deviation
0.069
Annual Variance
0.005
Information Ratio
-0.387
Tracking Error
0.205
Treynor Ratio
-2.494
Total Fees
$1652.83
Estimated Strategy Capacity
$61000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
#

class OpeningRangeBreakout(QCAlgorithm):
    
    # Order ticket for our stop order, Datetime when stop order was last hit
    
    stopMarketOrderFillTime = datetime.min
    stopMarketOrderShortFillTime = datetime.min
    
    

    def Initialize(self):
        self.SetStartDate(2019, 5, 5)  
        self.SetEndDate(2022, 5, 5)  
        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 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)
            
            #3. Print the new stop price with Debug()
            #self.Debug("SPY: " + str(self.highestSPYPrice) + " Stop: " + str(updateFields.StopPrice)) 
            
    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