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