{"record":{"id":"29bf65963d828864","repo":"QuantConnect/Lean","slug":"expected-filtered-universe-to-have-less-contracts","errorCode":null,"errorMessage":"Expected filtered universe to have less contracts than original universe. Filtered contracts count ({filtered_contracts}) is equal to total contracts count ({total_contracts})","messagePattern":"Expected filtered universe to have less contracts than original universe\\. Filtered contracts count \\((.+?)\\) is equal to total contracts count \\((.+?)\\)","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/OptionUniverseFilterGreeksRegressionAlgorithm.py","lineNumber":56,"sourceCode":"        self._max_theta = -182.5\n        self._min_rho = 0.5\n        self._max_rho = 3.0\n        self._min_iv = 1.0\n        self._max_iv = 3.0\n        self._min_open_interest = 100\n        self._max_open_interest = 500\n\n        option.set_filter(self.main_filter)\n        self.option_chain_received = False\n\n    def main_filter(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:\n        total_contracts = len(list(universe))\n\n        filtered_universe = self.option_filter(universe)\n        filtered_contracts = len(list(filtered_universe))\n\n        if filtered_contracts == total_contracts:\n            raise AssertionError(f\"Expected filtered universe to have less contracts than original universe. \"\n                                 f\"Filtered contracts count ({filtered_contracts}) is equal to total contracts count ({total_contracts})\")\n\n        return filtered_universe\n\n    def option_filter(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:\n        # Contracts can be filtered by greeks, implied volatility, open interest:\n        return universe \\\n            .delta(self._min_delta, self._max_delta) \\\n            .gamma(self._min_gamma, self._max_gamma) \\\n            .vega(self._min_vega, self._max_vega) \\\n            .theta(self._min_theta, self._max_theta) \\\n            .rho(self._min_rho, self._max_rho) \\\n            .implied_volatility(self._min_iv, self._max_iv) \\\n            .open_interest(self._min_open_interest, self._max_open_interest)\n\n        # Note: there are also shortcuts for these filter methods:\n        '''\n        return universe \\","sourceCodeStart":38,"sourceCodeEnd":74,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/OptionUniverseFilterGreeksRegressionAlgorithm.py#L38-L74","documentation":"In OptionUniverseFilterGreeksRegressionAlgorithm, the option universe filter chains .delta().gamma().vega().theta().rho().implied_volatility().open_interest() on the OptionFilterUniverse. The assertion in the filter callback checks that the filtered universe actually shrank relative to the original — i.e. at least one contract was removed by the Greek/IV/OI predicates. Equality means the filter ranges were so wide that nothing was excluded, which would make the regression useless at proving the filter works.","triggerScenarios":"set_filter callback computes total_contracts = len(list(universe)), applies the chained Greek/IV/OI filter, then len(list(filtered_universe)) == total_contracts. Triggered when every contract in the universe already satisfies all filter bounds (ranges too permissive), or when the filter methods are no-ops due to a Lean engine regression.","commonSituations":"Widening the min/max Greek bounds so all contracts pass; a Lean change making OptionFilterUniverse greek/IV/OI filters not actually prune; running on a data package where the universe is tiny and happens to all fit the ranges.","solutions":["Tighten at least one filter range (delta, gamma, vega, theta, rho, IV, or open interest) so some contracts are excluded.","If testing the engine, verify the OptionFilterUniverse filter methods actually remove non-matching contracts (diff the filter implementation).","Print total vs filtered counts during development to tune ranges against the regression data.","Ensure the regression data for GOOG on the test date contains contracts spanning the filter boundaries."],"exampleFix":"# before: ranges too wide, nothing filtered\nself._min_delta, self._max_delta = -10.0, 10.0\n# after: a range that excludes some contracts\nself._min_delta, self._max_delta = 0.5, 1.5","handlingStrategy":"validation","validationCode":"# Validate the filter actually prunes before returning it\ndef main_filter(self, universe):\n    total = len(list(universe))\n    filtered = self.option_filter(universe)\n    # option_filter returns an enumerable; materialize once\n    filtered_list = list(filtered)\n    if len(filtered_list) >= total and total > 0:\n        # ranges too wide; log and proceed (or tighten ranges in config)\n        self.log(f'warning: filter did not reduce universe ({total})')\n    return filtered_list","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Tune filter ranges against the actual universe so some contracts are excluded.","Materialize the filtered enumerable once to avoid double-iteration surprises.","When testing the engine, verify OptionFilterUniverse methods truly prune.","Print total vs filtered counts while developing."],"tags":["options","universe-filter","greeks","regression-test","quantconnect"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}