Ive been learning from the community here and would like to put this out there to help anyone else who has been having difficulties making their strategies work with futures contacts. This is a simple BB system but it shows you how to add your indicator and update through history functions and that is a great starting template for most simple systems you might be trying to implement. Best Regards, Aegeanfutures
import pandas as pd
class BollingerBandsAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 1) #Set Start Date
self.SetEndDate(2020, 1, 1) #Set End Date
self.SetCash(100000) #Set Strategy Cash
self.new_day = True
self.contract = None
# Subscribe and set our expiry filter for the futures chain
futureES = self.AddFuture(Futures.Indices.SP500EMini)
futureES.SetFilter(TimeSpan.FromDays(30), TimeSpan.FromDays(720))
self.bb_period = 50
self.bb_dev = 4
def OnData(self, slice):
self.InitUpdateContract(slice)
def InitUpdateContract(self, slice):
# Reset daily - everyday we check whether futures need to be rolled
if not self.new_day:
return
if self.contract != None and (self.contract.Expiry - self.Time).days >= 3: # rolling 3 days before expiry
return
for chain in slice.FutureChains.Values:
# If we trading a contract, send to log how many days until the contract's expiry
if self.contract != None:
self.Log('Expiry days away {} - {}'.format((self.contract.Expiry-self.Time).days, self.contract.Expiry))
# Reset any open positions based on a contract rollover.
self.Log('RESET: closing all positions')
self.Liquidate()
# get list of contracts
contracts = list(chain.Contracts.Values)
chain_contracts = list(contracts) #[contract for contract in chain]
# order list of contracts by expiry date: newest --> oldest
chain_contracts = sorted(chain_contracts, key=lambda x: x.Expiry)
# pick out contract and log contract name
self.contract = chain_contracts[1]
self.Log("Setting contract to: {}".format(self.contract.Symbol.Value))
# Set up consolidators.
one_hour = TradeBarConsolidator(TimeSpan.FromMinutes(60))
one_hour.DataConsolidated += self.OnHour
self.SubscriptionManager.AddConsolidator(self.contract.Symbol, one_hour)
# Set up indicators
self.Bolband = self.BB(self.contract.Symbol, self.bb_period, self.bb_dev, MovingAverageType.Simple, Resolution.Hour)
history = self.History(self.contract.Symbol, self.bb_period*60, Resolution.Minute).reset_index(drop=False)
for bar in history.itertuples():
if bar.time.minute == 0 and ((self.Time-bar.time)/pd.Timedelta(minutes=1)) >= 2:
self.Bolband.Update(bar.time, bar.close)
self.new_day = False
def OnHour(self, sender, bar):
if (self.Bolband != None and self.Bolband.IsReady) :
if bar.Symbol == self.contract.Symbol:
price = bar.Close
holdings = self.Portfolio[self.contract.Symbol].Quantity
# buy if price closes below lower bollinger band
if holdings <= 0 and price < self.Bolband.LowerBand.Current.Value:
self.Log("BUY >> {}".format(price))
self.MarketOrder(self.contract.Symbol, 1)
if holdings <= 0 and price > self.Bolband.UpperBand.Current.Value:
self.Log("Sell >> {}".format(price))
self.MarketOrder(self.contract.Symbol, -1)
# sell if price closes above the upper bollinger band
if self.Portfolio[self.contract.Symbol].IsLong and price > self.Bolband.UpperBand.Current.Value:
self.Log("SELL >> {}".format(price))
self.Liquidate()
if self.Portfolio[self.contract.Symbol].IsShort and price < self.Bolband.LowerBand.Current.Value:
self.Log("Buy >> {}".format(price))
self.Liquidate()
self.Plot("BB", "MiddleBand", self.Bolband.MiddleBand.Current.Value)
self.Plot("BB", "UpperBand", self.Bolband.UpperBand.Current.Value)
self.Plot("BB", "LowerBand", self.Bolband.LowerBand.Current.Value)
else:
self.Log('Bollinger Bands not ready yet')
def OnEndOfDay(self):
self.new_day = True
Vladimir
AegeanFutures
Thank you for sharing.
Here is "SPY Bollinger Band LE with Stop Loss and Take Profit" that can be another starting template.
David Lelong
Hi Vladimir,
I'm trying to turn this strategy into a library strategy that I can call in a main algorithm.
The library strategy looks like:
However, when I run I get the following error:
Any ideas on what needs to be adjusted?
Thanks in advance,
David
Fred Painchaud
Hi David,
If I may, change this block
with this block:
You're doing side effects on your QCAlgorithm (I'm assuming self.control_self is a ref to your algo) from your QQQLibrary class however, which is not super safe but it may work nevertheless.
Fred
David Lelong
Hi Fred,
I made the adjustments, and I'm now seeing this error:
Please advise.
Thanks in advance,
David
Fred Painchaud
Hi David,
I basically went for the second way of registering consolidators. The first way complained about the required param not being there and now it does about the two required params not being there. But in both cases they are there.
I'm wondering if the error does not come from somewhere else. Would it be possible to post also the code that uses that library?
Fred
David Lelong
Hi Fred,
Here's the relevant code from the main algorithm that calls the library:
And here's the full code for the QQQLibrary. The other libraries work fine.
Thanks,
David
Fred Painchaud
Got it.
Yeah, the error was coming from your main algo.
You are registering a scheduled event:
self.Schedule.On(self.DateRules.EveryDay("SPY"),self.TimeRules.BeforeMarketClose("SPY",5), self.qqq.BarHandler)
However, BarHandler takes one param, right now. And it took 2 with my code. But event handlers are not designed to call methods with params. They have no way to know which params to pass to the scheduled function (here BarHandler). Hence the error you get missing one param or 2 params, or whatever the number of params you put to BarHandler.
BarHandler is programmed to respond to your consolidator's consolidated bar events. THOSE use either 1 or 2 params, depending on how the registration is done.
So in a nutshell, you need to schedule your rule above to call a method without any params other than self. Here, it does not make sense to make it call BarHandler as the scheduler cannot send you consolidated data. You will need to define another method inside QQQLibrary with only self as param that you want to call 5 minutes before market close on each day SPY is open…
Fred
AegeanFutures
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!