from AlgorithmImports import *
class PivotBasedTradingAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2024, 1, 1)
# self.SetEndDate(2020, 1, 1)
self.SetCash(100000)
self.Debug(f"The algorithm time zone is set to: {self.TimeZone}")
self.SetTimeZone("America/New_York")
# Set brokerage model
self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin)
# Add symbol with 5-minute resolution
# Add symbol
self.symbol = self.AddEquity("SPY", Resolution.Minute).Symbol
# Create a 5-minute consolidator
five_minute_consolidator = TradeBarConsolidator(timedelta(minutes=5))
five_minute_consolidator.DataConsolidated += self.OnDataConsolidated
self.SubscriptionManager.AddConsolidator(self.symbol, five_minute_consolidator)
# Create a daily consolidator
daily_consolidator = TradeBarConsolidator(timedelta(days=1))
daily_consolidator.DataConsolidated += self.DailyDataConsolidated
self.SubscriptionManager.AddConsolidator(self.symbol, daily_consolidator)
# Schedule function to liquidate 15 minutes before market close
self.Schedule.On(self.DateRules.EveryDay(self.symbol),
self.TimeRules.BeforeMarketClose(self.symbol, 15),
self.LiquidatePosition)
# Initialize RollingWindow for high, low, and close
self.highWindow = RollingWindow[float](2) # Holds the last 2 high prices
self.lowWindow = RollingWindow[float](2) # Holds the last 2 low prices
self.closeWindow = RollingWindow[float](2) # Holds the last 2 close prices
# Initialize pivot point attributes
self.r1 = None
self.r2 = None
self.s1 = None
self.s2 = None
# Warm up the RollingWindows
self.SetWarmUp(2, Resolution.Daily)
def DailyDataConsolidated(self, sender, bar):
# This handler is called when the daily consolidator publishes a new consolidated bar
if self.IsWarmingUp:
return
# Add the new data to the rolling windows for daily high, low, and close
self.highWindow.Add(bar.High)
self.lowWindow.Add(bar.Low)
self.closeWindow.Add(bar.Close)
# Calculate pivot points using daily data
self.CalculatePivotPoints()
def OnDataConsolidated(self, sender, bar):
'''
This is called for each 5-minute bar of data. If the pivot points haven't been calculated yet (they are None), it returns early.
If it's the first 5-minute bar of the day (9:30 AM), it calculates the pivot points.
The trading logic checks if the current bar's closing price is greater than r1 to enter a long position or if it's less than r1 to exit the position.
'''
if self.IsWarmingUp:
return
self.Debug(f"Processing bar for {bar.EndTime}: Close={bar.Close}")
# Skip if pivot points haven't been calculated yet
if self.r1 is None or self.r2 is None or self.s1 is None or self.s2 is None:
self.Debug(f"Pivot points not yet calculated {self.Time}")
return
self.Debug(f"Pivot points: R1={self.r1}, R2={self.r2}, S1={self.s1}, S2={self.s2}")
# Trading logic
if bar.Close > self.r1 and not self.Portfolio.Invested:
self.Debug(f"Signal to go Long: 5m Close: {bar.Close} > R1: {self.r1}")
self.SetHoldings(self.symbol, 1) # Long entry
elif self.Portfolio.Invested and bar.Close < self.r1:
self.Debug(f"Signal to go Close: 5m Close: {bar.Close} < R1: {self.r1}")
self.Liquidate() # Exit position
def CalculatePivotPoints(self):
'''
Calculates the pivot points using the previous day's high, low, and close prices.
This method is called at the beginning of the trading day to set the r1, r2, s1, and s2 values.
'''
# Check if rolling windows are ready if not, return
if not (self.highWindow.IsReady and self.lowWindow.IsReady and self.closeWindow.IsReady):
self.Debug("Not enough data to calculate pivot points.")
return
previousHigh = self.highWindow[1]
previousLow = self.lowWindow[1]
previousClose = self.closeWindow[1]
self.Debug(f"Stored previous day's OHLC: High={previousHigh}, Low={previousLow}, Close={previousClose}")
# If variables are set and ready, calculare the pivot levels
if previousHigh is not None and previousLow is not None and previousClose is not None:
p = (previousHigh + previousLow + previousClose) / 3
self.r1 = 2 * p - previousLow
self.r2 = p + (previousHigh - previousLow)
self.s1 = 2 * p - previousHigh
self.s2 = p - (previousHigh - previousLow)
self.Debug(f"Calculated Pivot Points - R1: {self.r1}, R2: {self.r2}, S1: {self.s1}, S2: {self.s2}")
else:
self.Debug("Cannot calculate pivot points.")
def LiquidatePosition(self):
'''
Liquidates any invested position 15 minutes before the market close.
'''
# Liquidate 15 minutes before market close
if self.Portfolio.Invested:
self.Liquidate(self.symbol)
I am trying to get data consolidators to work. I shared a backtest which does not execute any trades but I have since updated my code and get the following error: I will also share my updated blcok of code leading to this error. Any help in understanding and resolving this issue would be greatly appreciated. I believe I am properly setting up the consolidators for my trading logic but it just does not process correctly. I would really love to undertand what I am doing wrong. I am using a 5minute and daily consolidator after subscribing to the asset's minutely data.
Ashutosh
Hi Akira
I backtested your code and was not hit by your mentioned hiccup.
Your consolidator implementation is good as you have used minute resolution to consolidate 5-minute bars.
The kind of error you have posted is hit when you use a higher-resolution bar to consolidate a lower-resolution bar (not in this case).
I just made a small change in assigning levels inside the “CalculatePivotPoints" method.
The code is working fine and I have attached the backtest.
Let me know if you have other concerns. Happy to help.
Best,
Ashutosh
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
Akira
The material on this website is provided for informational purposes only and does not constitute an offer to sell, a solicitation to buy, or a recommendation or endorsement for any security or strategy, nor does it constitute an offer to provide investment advisory services by QuantConnect. In addition, the material offers no opinion with respect to the suitability of any security or specific investment. QuantConnect makes no guarantees as to the accuracy or completeness of the views expressed in the website. The views are subject to change, and may have become unreliable for various reasons, including changes in market conditions or economic circumstances. All investments involve risk, including loss of principal. You should consult with an investment professional before making any investment decisions.
To unlock posting to the community forums please complete at least 30% of Boot Camp.
You can continue your Boot Camp training progress from the terminal. We hope to see you in the community soon!