Hi all,
I've seen a similar issue raised here before, but the answer was quite specific to the individual's code and I couldn't figure out how to apply the solution to mine. It sounds like this error is raised when a function tries to use a returned null value or something along those lines. I have used the debugger and I believe the issue arises when I try to make my itm_calls list (line 162) as that's where the debugger is getting stuck. I was able to have this algorithm make proper trades when I first tried it with shares, but now I am having trouble implementing options. I got the options buying code from “Options Trading Algorithm in Python - Code Along” by TradeOptionsWithMe on Youtube, but I had to modify it a little bit as he wanted out of the money puts and I want itm calls, specifically the first itm call with an expiration date of 0. As I progress I want to add in a sort of “if current time is past 1pm, buy contract with 1dte” but baby steps haha. The other piece of information that I think is worth noting, is that my algo decides to buy during an EventHandler which is called each time the consolidator pushes two 1min bars into one 2min bar. With that being said, I dont think you can order the option within the event handler because you need slice:data to retrieve the options chain (I think). To get around this, I have the eventhandler set a “buyCallFlag” and then the onData has an if statement waiting for that flag to flip true so it can call BuyCall(). Please forgive the dirty code, this is clearly still in building phase which is why so many “attempts” are commented out. I have also commented out my strategy for security purposes, but feel free to implement a buy condition in the same spot to test the option purchasing. Line 110 is where I have the buy condition. I appreciate the help and patience with this potentially “nubey” question!! Oh, I also paid for a $10 month subscription, but I still have the 20 second backtest delay.. Do I really need to pay more just to avoid the darn delay?? Super sorry that I am only able to insert code block, I am unable to attach a recent backtest as they all have runtime errors and thus wont appear on the backtest drop down menu when I try to insert backtest, and the most recent successful run is not close to the code now and has the strategy in it as well.
# region imports
from AlgorithmImports import *
from datetime import timedelta
#from QuantConnect.Data.Custom.CBOE import *
# endregion
class HyperActiveTanCow(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2023, 2, 22) # Set Start Date
self.SetEndDate(2023, 2, 27)
self.SetCash(100000) # Set Strategy Cash
self.equity = self.AddEquity("SPY", Resolution.Minute) # Add the underlying stock: Spy
self.equity.SetDataNormalizationMode(DataNormalizationMode.Raw)
self.symbol = self.equity.Symbol
#self.SetBenchmark(self.equity)
#option = self.AddOption("SPY", Resolution.Minute) # Add the option corresponding to underlying stock
#self.symbol = option.Symbol #can now symbol back and forth
self.contract = str()
self.contractsAdded = set()
#create array to track n amount of 2min ewo bars
self.ewoTracker = []
#this is the array iterator to count each entry space/element
self.i = -1
self.needToPop = False
self.haveHoldings = False
self.buyBar = 0
self.buyCallFlag = False
#Have the algo only look at contracts that are 1 row above or below the strike price and 0 or 1dte
#option.SetFilter(-1, 1, timedelta(0), timedelta(0))
#Create two min consolidator, attach event handler for every 2min, then add consolidator to the engines subscription manager for updates
twoMinConsolidator = TradeBarConsolidator(timedelta(minutes=2))
twoMinConsolidator.DataConsolidated += self.TwoMinBarHandler
self.SubscriptionManager.AddConsolidator("SPY", twoMinConsolidator)
#Create EMA indicators
self.ema5 = ExponentialMovingAverage(5, 0.33)
self.ema35 = ExponentialMovingAverage(35, 0.055)
#Have indicator work w 2min bars
self.RegisterIndicator("SPY", self.ema5, twoMinConsolidator)
self.RegisterIndicator("SPY", self.ema35, twoMinConsolidator)
self.SetWarmUp(timedelta(35))
#Create a scheduled event that sells all holdings before close of day
self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.BeforeMarketClose("SPY", 1), self.ClosePositions)
def OnData(self, data: Slice):
#Ensure indicators are warmed up
if not self.ema5.IsReady and self.ema35.IsReady:
return
self.Plot("ExponentialMovingAverage", "ema5", self.ema5.Current.Value)
self.Plot("ExponentialMovingAverage", "ema35", self.ema35.Current.Value)
#option_invested = [x.Key for x in self.Portfolio if x.Value.Invested and x.Value.Type == SecurityType.Option]
#If two min bar handler flips buy call flag from false to true, then create options chain and call BuyCall()
#if self.buyCallFlag:
#for j in data.OptionChains: #This was from video #12
# self.Debug("Recognized")
# chains = j.Value
# self.BuyCall(chains)
#self.buyCallFlag = False
if self.buyCallFlag:
self.BuyCall(data)
#if option_invested:
#monitor premium price to decide when to sell
#pass
def TwoMinBarHandler(self, sender, consolidated):
#ema5 - ema35 to get 2minEWO value
self.twoMinEWO = float(self.ema5.Current.Value - self.ema35.Current.Value)
#Add current ewo bar to array to track n most recent (still need to implement pop)
self.ewoTracker.append(self.twoMinEWO)
self.i += 1
#Use this block at the end of function call to pop 5th most recent bar to keep storage down
#if self.i >= 4:
# self.needToPop = True
#if self.needToPop:
# self.ewoTracker.pop(self.i - 4)
#Use this to constantly print the EWO array in 5 bar intervals
#if ((self.i+1) % 5 == 0):
#self.Debug(str(self.ewoTracker[self.i-4]) + ", " + str(self.ewoTracker[self.i-3]) + ", " + str(self.ewoTracker[self.i-2]) + ", " + str(self.ewoTracker[self.i-1]) + ", " + str(self.ewoTracker[self.i]))
#self.Debug(str(self.Time))
#Deciding Entry (ONLY 2min red to green flips with CALLS)
#took out the strategy for security purposes
if (self.i >= 3):
#took out strategy, feel free to implement some sort of buy condition for testing
#self.MarketOrder("SPY", 100)
#Call BuyCall function
self.buyCallFlag = True
self.Debug("Buy")
self.Debug(str(self.Time))
self.buyBar = self.i
#Quick test logic to sell after 10mins of holding the position
#if it is 5 bars after buying, sell
#if (self.i == (self.buyBar + 5)):
#self.MarketOrder("SPY", -100)
#self.Debug("Sell")
#self.Debug(str(self.Time))
#self.buyBar = 0
#Buy Call Function
#def BuyCall(self, chains):
#First try, didnt work, got it from TradeOptionsWithMe Video #12
#self.Debug("Buy Call1")
#expiry = sorted(chains, key = lambda x: x.Expiry, reverse=True)[0].Expiry
#calls = [i for i in chains if i.Expiry == expiry and i.Right == OptionRight.Call]
#call_contracts = sorted(calls, key = lambda x: abs(x.Strike - x.UnderlyingLastPrice))
#if len(call_contracts) == 0:
# return
#self.call = call_contracts[0]
#self.Debug(self.call.Expiry)
#self.Debug(self.call.Strike)
#quantity = self.Portfolio.TotalPortfolioValue / self.call.AskPrice
#quantity = int(0.05 * quantity / 100)
#self.Buy(self.call.Symbol, quantity)
#self.Debug("Buy Call2")
#This is from Coding an Options Trading Algoirthm in Python - Code Along
def BuyCall(self, data):
if self.contract == str():
self.contract = self.OptionsFilter(data)
return
elif not self.Portfolio[self.contract].Invested and data.ContainsKey(self.contract):
quantity = self.Portfolio.TotalPortfolioValue / self.call.AskPrice
#quantity = 100000 / self.call.AskPrice
quantity = int(0.05 * quantity / 100)
self.Buy(self.contract, quantity)
def OptionsFilter(self, data):
contracts = self.OptionChainProvider.GetOptionContractList(self.symbol, data.Time)
self.underlyingPrice = self.Securities[self.symbol].Price
itm_calls = [i for i in contracts if i.ID.OptionRight == OptionRight.Call and
i.ID.StrikePrice - self.underlyingPrice > 0 and i.ID.StrikePrice - self.underlyingPrice < 1 and
(i.ID.Date - data.Time).days == 0]
self.Debug(str(itm_calls))
if len(itm_calls) > 0:
self.Debug("Buy Call")
self.Debug(str(itm_calls))
#Liquidate any holdings before close of day
def ClosePositions(self):
self.i = -1
if self.Portfolio.Invested:
self.Liquidate()
#Next step is learning to market buy ATM 0dte options, but not 0dte if after 1pm
#Then tracking the premium and figuring out when to sell based off of percentages
#Then market sell
Nico Xenox
Hey jclute17,
in your code you dont return nothing after selecting itm_contracts. The could should look something like this:
Also I would rewrite this:
to this:
The reason for this is that it does not have that symbol in the symbolcache and it will give you an error.
If you're satisfied with my answer please don't forget to accept it 😊
Hope it helps ;)
Nico Xenox
Here's a simple strategy that I wrote I while ago about 0-7dte options. The objective is to sell options before market close if the current price is higher than the opening price.
Might help you on the way, happy coding! 😊
Jclute17
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!