I have been trying to get options contracts using OptionChainProvider.GetOptionContractList rather than subscribing to option chains via AddOption, as it seems to be much more efficient in backtesting. I was having trouble getting the actual OptionContract, however I think I am most of the way there. I want to share my progress with this community (at Alex's suggestion) so it can be a learning resource for other users trying to accomplish similar tasks. 

Here is the code that I call in the OnData() method for each time step to get a 5% OTM call contract for a given security:

def GetCallContract(self, data, symbol): # Last price of the underlying px_last = data[symbol].Close # Get contracts contracts = self.OptionChainProvider.GetOptionContractList(symbol, data.Time) # Get the call options calls = [x for x in contracts if x.ID.OptionRight == 0] # Choose OTM contracts otm = [x for x in calls if px_last - x.ID.StrikePrice < 0] # Get 3-6 month contracts otm_3_month = [x for x in otm if x.ID.Date >= (self.Time + relativedelta(months=+3)) and x.ID.Date < (self.Time + relativedelta(months=+6))] # Go 5% OTM otm_5_to_7 = [x for x in otm_3_month if x.ID.StrikePrice >= px_last * 1.05] # Sort by strike price then by soonest expiry sorted_contracts = list(sorted(otm_5_to_7, key = lambda x: (x.ID.StrikePrice, x.ID.Date))) # Exit if there are no contracts if len(sorted_contracts) == 0: return None # Use AddOptionContract() to subscribe to this contract self.AddOptionContract(sorted_contracts[0], Resolution.Minute) return sorted_contracts[0]

I was having difficulty getting things like AskPrice etc. from the Symbol returned from this call, but it turns out I can get the SecurityIdentifier from self.Securities[contract_id]:

contract_id = self.GetCallContract(data, symbol) if contract_id is None: continue # Get the contract contract = self.Securities[contract_id]

With the above lookup by option contract symbol, I can now access things contract.AskPrice, contract.StrikePrice, contract.Expiry, etc. 


The only remaining issue is that I often end up with the following error:

Backtest Handled Error: The security with symbol 'SBUX 180420C00062500' is marked as non-tradable.

I have seen in other forum posts (that I cannot seem to locate again) that I need to wait one time-step between subscribing to an option contract with self.AddOptionContract(contract_id) and actually attempting to trade it. If this is the case, how should I go about fixing my pattern? As it stands, I call GetCallContract() in my OnData method, once for each security in my universe. I need to then immediately access the current market pricing of that contract and trade it if necessary.


Thank you, and I hope this discussion will be useful to others in similar situations!