QuantConnect/Lean · error · RegressionTestException
Expected at least two future contracts with option chains, b
Error message
Expected at least two future contracts with option chains, but found {} What it means
Thrown by a regression-test assertion inside validate_option_chains when a FutureOption algorithm's data slice yields zero future contracts that carry a populated option chain. The algorithm iterates slice.future_chains, looks up each contract symbol in slice.option_chains, and counts how many have a non-empty chain. If the count is less than 1 it aborts, signalling the future-filter / option-filter wiring did not surface any tradeable option chains. NOTE: the message text 'at least two' is misleading — the guard is actually '< 1', so a single qualifying contract passes.
Source
Thrown at Algorithm.Python/FutureOptionWithFutureFilterRegressionAlgorithm.py:39
### </summary>
class FutureOptionWithFutureFilterRegressionAlgorithm(FutureOptionContinuousFutureRegressionAlgorithm):
def set_filter(self):
"""Set future filter for specific contracts"""
self.future.set_filter(0, 368)
def validate_option_chains(self, slice: Slice):
future_contracts_with_option_chains = 0
for future_chain in slice.future_chains.values():
for future_contract in future_chain:
# Not all future contracts have option chains, so we need to check if the contract is in the option chain
if future_contract.symbol in slice.option_chains:
chain = slice.option_chains[future_contract.symbol]
if len(chain) == 0:
raise RegressionTestException("Expected at least one option contract for {}".format(chain.symbol))
future_contracts_with_option_chains += 1
if future_contracts_with_option_chains < 1:
raise RegressionTestException("Expected at least two future contracts with option chains, but found {}".format(future_contracts_with_option_chains))View on GitHub (pinned to d2c3659f87)
Solutions
- Confirm the backtest date range actually has option-chain data for the futures the filter returns (check the /Data folder for matching OPRA/CME FOP files).
- Adjust set_filter(0, 368) bounds so at least one returned future contract has a matching option chain in slice.option_chains.
- Verify the future_contract.symbol lookup key matches the option chain keys exactly (canonical vs mapped symbol mismatch).
- If authoring a new regression, raise the bar correctly — the message says 'two' but code checks '< 1'; align the message with the intended threshold.
Example fix
// before self.future.set_filter(0, 368) // after - widen so contracts with listed options are included self.future.set_filter(0, 700)
Defensive patterns
Strategy: validation
Validate before calling
# Before relying on option chains, count qualifying future contracts
count = 0
for future_chain in slice.future_chains.values():
for fc in future_chain:
if fc.symbol in slice.option_chains and len(slice.option_chains[fc.symbol]) > 0:
count += 1
if count < 1:
self.debug(f"No future contracts with option chains at {self.time}; skipping")
return Type guard
def has_option_chain_for_future(slice: Slice, future_symbol: Symbol) -> bool:
return future_symbol in slice.option_chains and len(slice.option_chains[future_symbol]) > 0 Prevention
- Validate slice.option_chains membership and length before counting.
- Keep future set_filter and option filter ranges overlapping so at least one contract has options.
- In regression tests, align assertion thresholds with message text to avoid confusion.
- Log future_contract.symbol vs option_chains keys when debugging mismatches.
When it happens
Trigger: Calling add_future + add_future_option with a set_filter that returns no overlapping contracts; a data date where the continuous-future canonical maps to a contract that has no listed options; or the option filter (FutureOptionContinuousFutureRegressionAlgorithm base) excluding every contract the future filter returned.
Common situations: Changing the future set_filter range so it no longer includes contracts that have option chains; running the regression against a data drop missing the option chain files; a Symbol mapping change so future_contract.symbol never matches an option_chains key; version updates that alter the default FutureOption univer generation.
Related errors
- [{UtcTime}] We hold a delisted securities: {string.Join(",",
- We expected some FOP trading to happen
- Expiry warning with time {delisting.time} but is expected to
- Delisting warning received at an unexpected date: {self.time
- Delisting occurred at unexpected time: {delisting.time} - ex
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/601c014c47f63779.
Report an issue: GitHub.