Hi, I've been trying to backtest locally using the CLI and daily EOD option data I had laying around from IVolatility. Right now, my code to handle custom data looks like this:
class OptionContract(PythonData):
def __init__(self, symbol, value, time):
super().__init__()
self.Symbol = symbol
self.Value = value
self.Time = time
class IVolatilityChain(PythonData):
def GetSource(self, config, date, isLive):
if isLive:
raise NotImplementedError
symbol = config.Symbol.Value
date_str = date.strftime('%d-%m-%Y')
request = "http://localhost:5000/IVolatility?date={}&underlying={}".format(date_str, symbol)
return SubscriptionDataSource(request, SubscriptionTransportMedium.Rest)
def Reader(self, config, line, date, isLive):
data = json.loads(line)
chain = IVolatilityChain()
chain.Symbol = config.Symbol
chain.Value = 0
chain.Time = data[0]['DataDate']
option_contracts = []
for option_contract in data:
option_contracts.append(OptionContract(symbol=option_contract['OptionSymbol'].replace(" ", "_"),
value=option_contract['MeanPrice'],
time=option_contract['DataDate']))
chain['Chain'] = option_contracts
return chain
class SomeAlgorithm(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2018, 1, 8)
self.SetEndDate(2018, 1, 8)
self.SetCash(100000)
self.AddData(IVolatilityChain, "AAPL", Resolution.Daily)
def OnData(self, data):
chain = data['AAPL.IVolatilityChain'].Chain
contract = chain[0]
# throws exception due to individual option contract symbol not being registered:
self.Order(contract.Symbol, 1)
Given the underlying and current date, the relevant option chain is fetched. This works. The custom data object gets registered as ‘AAPL.IVolatilityChain’ and I can access it in the OnData method. However, the individual option contracts within the chain never get subscribed/registered anywhere, making it impossible to order them. Can anyone provide any pointers on how I should handle this case?
Jasper van Merle
Hi Tdrxy,
The problem is most likely on line 16. When you run a backtest with the CLI, the CLI runs LEAN in a Docker container. This means that localhost resolves to the localhost of the Docker container, instead of the localhost of your host machine. If you replace “localhost:5000” with “host.docker.internal:5000”, requests will be sent to port 5000 of your host machine instead of port 5000 of the Docker container.
Tdrxy
Hi Jasper, Thanks for the reply! The REST API is working just fine, in my actual code I use the host IP. The problem lies with individual contract symbols not being registered in the universe. I have no idea how to do that without registering each individual symbol in the init method. ‘host.docker.internal’ does not work for Linux hosts btw.
Jasper van Merle
Hi Tdrxy,
“‘host.docker.internal’ does not work for Linux hosts btw.”
Normally you'd be right, but when you use the CLI on Linux it automatically adds an extra host entry to the Docker container so that host.docker.internal works like it does on Windows and macOS. If it doesn't work properly then that's a bug in the CLI.
“The problem lies with individual contract symbols not being registered in the universe. I have no idea how to do that without registering each individual symbol in the init method.”
I'm afraid I don't know the solution to this either, so I'll leave this part of the message to someone else.
Louis Szeto
Hi Tdrxy
We suggest you store your custom data Security object in a variable for later retrieval, as "AAPL.IVolatilityChain" may not be the symbol value that LEAN stores. Also, please avoid using the same symbol value with other tickers (the AAPL equity). You may find this doc for details and examples.
You may use .AddOptionContract to access the chain list for registration. Please see the attached backtest example. To suit your condition, instead of using contracts[0], please compare option_contract['OptionSymbol'] returns from contracts against the security identifiers/symbol returned from the OptionChainProvider to subscribe to the correct contract.
Best,
Louis Szeto
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.
Tdrxy
Hi Louis Szeto,
Thanks for your reply, but this doesn't seem to solve it. The method AddOptionContract requires a symbol as input, not a contract. In my case, this would result in a TypeError. If I do try the add the option contract with the symbol i.e.:
It results in a KeyError where Lean tries to look up the security belonging to said symbol:
The problem remains: I can register a custom object representing an option chain, but I can't add the chain its individual option contracts as securities into the universe.
In my eyes, I could solve this simply by doing away with the concept of an ‘option chain’, and register each individual option contract at the beginning of the algorithm, or dynamically during runtime. Instead of having a IVolatilityChain that overrides GetSource and Reader, I could go with IVolatilityOptionContract. However, this seems like a very crude way of going about this.
Louis Szeto
Hi Tdrxy
We can create a Symbol object if the string of your contract.Symbol.Value is the security identifier of the contract. For example:
If the string is in the format of AAPL 210618P00028750, we can use the CreateOption method to fetch the contract Symbol.
For further assistance, please share a few samples of your dataset
Best,
Louis Szeto
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.
Tdrxy
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!