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

Author