| 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