Overall Statistics
Total Trades
2
Average Win
0%
Average Loss
-0.07%
Compounding Annual Return
-0.072%
Drawdown
0.500%
Expectancy
-1
Net Profit
-0.072%
Sharpe Ratio
-31.846
Sortino Ratio
0
Probabilistic Sharpe Ratio
0.001%
Loss Rate
100%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.019
Beta
-0
Annual Standard Deviation
0.001
Annual Variance
0
Information Ratio
0.554
Tracking Error
0.202
Treynor Ratio
247.206
Total Fees
$2.52
Estimated Strategy Capacity
$33000000.00
Lowest Capacity Asset
QQQ RIWIV7K5Z9LX
Portfolio Turnover
0.55%
from AlgorithmImports import * 

class BootCampTask(QCAlgorithm):

    openingBar = None
    currentBar = None
    

    def Initialize(self):
        self.SetStartDate(2000, 1, 1)
        self.SetEndDate(2010, 1, 1)
        self.SetCash(100000)
        

        self.Debug(f"The algorithm time zone is set to: {self.TimeZone}")
        self.SetTimeZone("America/New_York")

        # Subscribe to $TSLA with minute resolution
        self.symbol = self.AddEquity("QQQ", Resolution.Minute).Symbol
        
        # Create our consolidator with a period of 30 mins
        consolidator = TradeBarConsolidator(timedelta(minutes=30))
        consolidator.DataConsolidated += self.consolidation_handler
        self.SubscriptionManager.AddConsolidator(self.symbol, consolidator)
        
        # Create a scheduled event triggered at 13:30 to call the ClosePositions function
        self.Schedule.On(self.DateRules.EveryDay(self.symbol),
                         self.TimeRules.BeforeMarketClose(self.symbol,30), 
                         self.ClosePositions)

    def OnData(self, data):
        # If the portfolio is currently invested or the opening bar is None, return
        if self.Portfolio.Invested or self.openingBar is None:
            return
        
        # Check if the close price is above the opening bar's high price, if so, go 100% Long on TSLA
        currentClose = data[self.symbol].Close
        if currentClose > self.openingBar.High:
            self.SetHoldings(self.symbol, 1)

        # Check if the close price is below the opening bar's low price, if so, go 100% short on TSLA
        elif currentClose < self.openingBar.Low:
            self.SetHoldings(self.symbol, -1)

    def consolidation_handler(self, sender, bar):
        # If it's the first 30 minutes bar after market open, set it as the opening bar
        if bar.Time.hour == 9 and bar.Time.minute == 30:
            self.openingBar = bar

    def ClosePositions(self):
        # Liquidate the position and reset the opening bar
        self.Liquidate(self.symbol)
        self.openingBar = None

        
        


from AlgorithmImports import *

class OpeningRangeBreakout(QCAlgorithm):

    '''
    This algorithm implements an Opening Range Breakout strategy which seeks to capitalize
    on the SPY's price movement above the first 5-minute bar's high after the market opens.
    
    The strategy works as follows:
    
    - At the start of each trading day, the price high of the first 5-minute bar is recorded
      as the 'opening range'.
      
    - The algorithm then monitors the market for any subsequent 5-minute bars that close above
      this 'opening range' high. When such a condition is met, the algorithm assumes a long position
      in the SPY, with the expectation that the upward trend will continue.
      
    - No new positions are taken after 12 PM, as the strategy only seeks morning breakouts.
    
    - A scheduled event ensures that any open position is liquidated 15 minutes before the market
      closes, to avoid holding positions overnight.

    Attributes:
    - openingBar: The first 5-minute bar of the day, used to define the opening range.
    - consolidator: A data consolidator for converting the minute-resolution data into 5-minute bars

    - OnData: Monitors the market data and takes a long position if the breakout condition is met.
    - OnFiveMinuteBar: Records the opening range high from the first 5-minute bar of the trading day.
    - ClosePositions: Liquidates any open positions 15 minutes before the market closes.
    ''' 
     
    def Initialize(self):
        self.SetStartDate(2022, 1, 1)  # Set Start Date
        self.SetEndDate(2022, 12, 31)  # Set End Date
        self.SetCash(100000)  # Set Strategy Cash
        self.symbol = self.AddEquity("QQQ", Resolution.Minute).Symbol
        self.SetTimeZone("America/New_York")

        # Consolidate minute data into 5-minute bars
        five_minute_consolidator = TradeBarConsolidator(timedelta(minutes=5))
        five_minute_consolidator.DataConsolidated += self.OnFiveMinuteBar
        self.SubscriptionManager.AddConsolidator(self.symbol, five_minute_consolidator)

        # Save the opening bar
        self.openingBar = None

        # Schedule the closing of positions 15 minutes before market close
        self.Schedule.On(self.DateRules.EveryDay(self.symbol),
                         self.TimeRules.BeforeMarketClose(self.symbol, 15),
                         self.ClosePositions)

    def OnData(self, data):
        # If it's past 12 PM, or we don't have an opening bar, or we're already invested, do nothing
        if self.Time.hour >= 12 or self.openingBar is None or self.Portfolio[self.symbol].Invested:
            return

        # Ensure there is data for the symbol
        if self.symbol not in data or data[self.symbol] is None:
            self.Debug(f"No data for {self.symbol} at {self.Time}")
            return

        # Check if the current bar's close is greater than the opening bar's high and enter a long position
        currentClose = data[self.symbol].Close  # Accessing Close price after confirming data availability
        if currentClose > self.openingBar.High:  # This line was causing the issue when openingBar was None
            self.SetHoldings(self.symbol, 1)
            self.Debug(f"Entered long position on {self.Time}")


    def OnFiveMinuteBar(self, sender, bar):
        # Ensure this is the first 5-minute bar of the trading day by checking if we haven't already set the openingBar
        if self.openingBar is None:
            # Check if the bar is within the first 5 minutes after market open
            # This handles cases where the first bar might not exactly align with the market open due to data feed start times
            if bar.Time.time() >= time(9, 30) and bar.Time.time() < time(9, 35):
                self.openingBar = bar
                self.Debug(f"Opening range high set to {self.openingBar.High} at {bar.Time}")
            else:
                self.Debug(f"First 5-minute bar missed, current bar time: {bar.Time}")



    def ClosePositions(self):
        # Close any positions that are open
        if self.Portfolio[self.symbol].Invested:
            self.Liquidate(self.symbol)
            self.Debug(f"Closed position on {self.Time}")
            self.openingBar = None  # Reset opening bar after closing position