Hello,
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!
Rahul Chowdhury
Hey Zachary,
When we subscribe to an option contract using AddOptionContract, the asset price is initially 0 because data for that contract has not yet been fed into the algorithm. We can work around this issue by using SetSecurityInitializer with a custom security initializer. We can create a custom security initializer which uses historical data to get the latest bar for our security and set that to the current market price, so that we can immediately place trades.
In Initialize
def Initialize(self): self.SetStartDate(2020, 2, 20) # Set Start Date self.SetCash(100000) # Set Strategy Cash .... self.SetSecurityInitializer(self.customSecurityInitializer)
Let's define our custom security initializer inside our main class.def customecurityInitializer(self, security): bar = self.GetLastKnownPrice(security) security.SetMarketPrice(bar)
GetLastKnownPrice returns the latest bar data for our security and using SetMarketPrice, we can use that bar data to place trades for that security right away.
Zachary Taylor
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!