{"record":{"id":"601c014c47f63779","repo":"QuantConnect/Lean","slug":"expected-at-least-two-future-contracts-with-option","errorCode":null,"errorMessage":"Expected at least two future contracts with option chains, but found {}","messagePattern":"Expected at least two future contracts with option chains, but found (.+?)","errorType":"exception","errorClass":"RegressionTestException","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/FutureOptionWithFutureFilterRegressionAlgorithm.py","lineNumber":39,"sourceCode":"### </summary>\nclass FutureOptionWithFutureFilterRegressionAlgorithm(FutureOptionContinuousFutureRegressionAlgorithm):\n    def set_filter(self):\n        \"\"\"Set future filter for specific contracts\"\"\"\n        self.future.set_filter(0, 368)\n    \n    def validate_option_chains(self, slice: Slice):\n        future_contracts_with_option_chains = 0\n        for future_chain in slice.future_chains.values():\n            for future_contract in future_chain:\n                # Not all future contracts have option chains, so we need to check if the contract is in the option chain\n                if future_contract.symbol in slice.option_chains:\n                    chain = slice.option_chains[future_contract.symbol]\n                    if len(chain) == 0:\n                        raise RegressionTestException(\"Expected at least one option contract for {}\".format(chain.symbol))\n                    future_contracts_with_option_chains += 1\n        \n        if future_contracts_with_option_chains < 1:\n            raise RegressionTestException(\"Expected at least two future contracts with option chains, but found {}\".format(future_contracts_with_option_chains))","sourceCodeStart":21,"sourceCodeEnd":39,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/FutureOptionWithFutureFilterRegressionAlgorithm.py#L21-L39","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nself.future.set_filter(0, 368)\n// after - widen so contracts with listed options are included\nself.future.set_filter(0, 700)","handlingStrategy":"validation","validationCode":"# Before relying on option chains, count qualifying future contracts\ncount = 0\nfor future_chain in slice.future_chains.values():\n    for fc in future_chain:\n        if fc.symbol in slice.option_chains and len(slice.option_chains[fc.symbol]) > 0:\n            count += 1\nif count < 1:\n    self.debug(f\"No future contracts with option chains at {self.time}; skipping\")\n    return","typeGuard":"def has_option_chain_for_future(slice: Slice, future_symbol: Symbol) -> bool:\n    return future_symbol in slice.option_chains and len(slice.option_chains[future_symbol]) > 0","tryCatchPattern":null,"preventionTips":["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."],"tags":["quantconnect","futures","future-options","regression-test","data-slice","option-chain"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}