QuantConnect / Lean

Lean Algorithmic Trading Engine by QuantConnect (Python, C#)
https://lean.io
Apache License 2.0
9.42k stars 3.2k forks source link

Should Live Option Chain Provider Return Expired Contracts? #6235

Closed AlexCatarino closed 1 year ago

AlexCatarino commented 2 years ago

Expected Behavior

LiveOptionChainProvider should not return expired contracts.

Actual Behavior

LiveOptionChainProvider may return expired contracts leading to the following runtime error when we try to subscribe it to IB:

Runtime Error: No security definition has been found for the request. Origin: [Id=23] Subscribe: SOFI 220225C00020000 (OPT SOFI USD Smart 20220225 20 C) Stack Trace: No security definition has been found for the request. Origin: [Id=23] Subscribe: SOFI 220225C00020000 (OPT SOFI USD Smart 20220225 20 C)

Potential Solution

a - Does LOCP need to return expired contracts? Does someone need/use it? If no reason can try filter internally directly b - Add an optional argument to filter out expired contract c - Or maybe add helper method to filter expired options

Reproducing the Problem

Call

contracts = self.OptionChainProvider.GetOptionContractList(Underlying, self.Time)

in a method right after the market opens. Do not add any logic to filter out expired contracts (assume they are not there), so you can call AddOptionContract for an expired contract.

Checklist

AlexCatarino commented 1 year ago

We have a probably related issue for Futures in backtesting where GetFutureContractList also returns expired contracts.

class VixSpread(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2011, 12, 29)  # Set Start Date
        self.AddEquity("SPY", Resolution.Minute)
        self.vix = Symbol.Create(Futures.Indices.VIX, SecurityType.Future, Market.CFE)

    def OnData(self, data: Slice):
        trade_date = self.Time
        contract_symbols = self.FutureChainProvider.GetFutureContractList(self.vix, trade_date)
        first = sorted(contract_symbols, key=lambda symbol: symbol.ID.Date)[0]
        if first.ID.Date < trade_date:
            raise Exception(f'{self.Time} :: First: {first.ID.Date} Trade {trade_date}')
jaredbroad commented 1 year ago

Ideally, we shouldn't require trade dates for algorithms at all (like other endpoints history etc)

Martin-Molinero commented 1 year ago

Ideally, we shouldn't require trade dates for algorithms at all (like other endpoints history etc)

Deferred for now, to be addressed separately as a feature/refactor.

TODOs here: