Hello I was asking for help as I am trying to code an algorithm that uses the vwap, inside bars and the 3 min timeframe for entries. I will attach my code below so you can see how far I have gotten. I have consolidated data into a 3 minute time frame. I have then put this consolidated data into a rollingWindow.
The purpose of this is that so the algo would be able to compare if the current bar is an inside bar or not without using too much space. My thought process was to have a rolling window of size 2 or 3 but I am asking so that I would be able to get the best implementation.
In short I need help with checking into my rollingWindow and validating that an Inside Bar is ready. The trade logic is if an Inside bar is ready and the current asset price is under the VWAP, the algorithm is to buy calls as soon as we break over the high of the inside bar. On the downside if an inside bar is ready and the asset price is over the VWAP we would buy puts at the break of the low of the inside bar.
class CalmFluorescentOrangeShark(QCAlgorithm):
def Initialize(self): ## symbol objects make way more information than tickers
self.SetStartDate(2022, 1, 1) # Set Start Date
self.SetEndDate(2022, 12, 30) # set end date
self.SetCash(100000) # Set Strategy Cash
self.symbol = self.AddEquity("SPY", Resolution.Minute)
self.symbol.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.equity = self.symbol
self.SetBenchmark(self.equity)
self.breakk = 0
self.InsideBar = ()
self.contract = str()
self.contractsAdded = set() # keeps track of how many contracts added to algo
self.DTE = 2 # buy options only within 2 days of expiration
self.OTM = 0.01 # To buy an option that is OTM by at least 1 percent
self.consolidator = self.Consolidate(self.symbol, timedelta(minutes=3), self.CustomBarHandler)
self.rollingWindow = RollingWindow[TradeBar](3) ## creating a rolling window with two trade bars
self.rollingWindow.Add(data["SPY"].Close) ## adding the close of the bar to be the data in the rolling window.
self.vwap = VolumeWeightedAveragePriceIndicator(10)
self.vwap.Updated += self.IndicatorUpdateMethod
self.RegisterIndicator(self.symbol, self.vwap, self.consolidator)
self.SetWarmup(timedelta(self.vwap))
def CustomBarHandler(self, bar):
self.currentBar = bar
self.rollingWindow.Add(self.currentBar) ## adding the consolidated three minute bar into the rolling window
def OnData(self, data):
if not self.rollingWindow.IsReady:
return
if not(self.Time.hour == 9 and self.Time.minute == 31):
return
if self.vwap.IsReady:
indicator_value = self.vwap.Current.Value
firstBar = self.rollingWindow[0]
L1 = firstBar.Low #low first candle
H1 = firstBar.High #high first candle
secondBar = self.rollingWindow[1]
L2 = secondBar.Low #low second candle
H2 = secondBar.High #high second candle
Bar = self.rollingWindow[1]
L2 = secondBar.Low #low second candle
H2 = secondBar.High #high second candle
for i in self.rollingWindow:
if self.RollingWindow[i].Low > self.RollingWindow[i-1].Low and self.RollingWindow[i].High < self.RollingWindow[i-1].High:
i += self.InsideBar
if data[self.symbol].Current.Value < indicator_value and data[self.symbol].Current.Value > self.InsideBar.High:
self.BuyCall(data)
pass
def OptionsFilter(self, data):
contracts = self.OptionChainProvider.GetOptionContractList(self.symbol, data.Time)
self.underlyingPrice = self.Securities[self.symbol].Price
otm_calls = [i for i in contracts if i.ID.OptionRight == OptionRight.Call and
i.ID.StrikePrice - self.underlyingPrice > self.OTM * self.underlyingPrice and
self.DTE - 2 < (i.ID.Date - data.Time).days < self.DTE + 2]
if len(otm_calls) > 0:
contract = sorted(sorted(otm_calls, key = lambda x : abs((x.ID.Date - self.Time).days - self.DTE)),
key = lambda x: x.ID.StrikePrice - self.underlyingPrice)[0]
if contract not in self.contractsAdded:
self.contractsAdded.add(contract)
self.AddOptionContract(contract, Resolution.Minute)
return contract
else:
return str()
def BuyCall(self, data):
quantity = self.Portfolio.Total.PortfolioValue / self.contract.AskPrice
quantity = int(0.05 * quantity / 100)
if self.contract == str():
self.contract = self.OptionsFilter(data)
return
elif not self.Portfolio[self.contract].Invested and data.ContainsKey(self.contract):
self.Buy(self.contract, quantity)
self.LimitOrder(self.contract, -quantity, (self.contract.AskPrice * .20))
self.StopMarketOrder(self.contract, - quantity, (self.call.AskPrice * 0.9))
def OnOrderEvent(self, orderEvent):
self.Log(str(orderEvent))
order = self.Transactions.GetOrderByID(orderEvent.OrderId)
if order.Status == OrderStatus.Filled:
if order.Type == OrderType.Limit or OrderType.StopMarket:
self.Transactions.CancelOpenOrders(order.contract)
if order.Status == OrderStatus.Canceled:
self.Log(str(orderEvent))
if order.Type == OrderType.OptionExercise:
self.Liquidate()
Louis Szeto
Hi Laurian
If you want to run the workflow only when the rolling window is updated, you can put the logic within OnData into the data consolidated event handler CustomBarHandler, and use self.CurrentSlice as the current updatest slice instance. That way you can skip all the checking if the rolling window, “insider bar” or other indicators are ready (given you've properly warmed up), while run the trading logic in the most efficient way.
Best
Louis
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.
Laurian Kimolo
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!