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