QuantConnect/Lean · error · AssertionError
Expected filtered universe to have less contracts than origi
Error message
Expected filtered universe to have less contracts than original universe. Filtered contracts count ({filtered_contracts}) is equal to total contracts count ({total_contracts}) What it means
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.
Source
Thrown at Algorithm.Python/OptionUniverseFilterGreeksRegressionAlgorithm.py:56
self._max_theta = -182.5
self._min_rho = 0.5
self._max_rho = 3.0
self._min_iv = 1.0
self._max_iv = 3.0
self._min_open_interest = 100
self._max_open_interest = 500
option.set_filter(self.main_filter)
self.option_chain_received = False
def main_filter(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:
total_contracts = len(list(universe))
filtered_universe = self.option_filter(universe)
filtered_contracts = len(list(filtered_universe))
if filtered_contracts == total_contracts:
raise AssertionError(f"Expected filtered universe to have less contracts than original universe. "
f"Filtered contracts count ({filtered_contracts}) is equal to total contracts count ({total_contracts})")
return filtered_universe
def option_filter(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:
# Contracts can be filtered by greeks, implied volatility, open interest:
return universe \
.delta(self._min_delta, self._max_delta) \
.gamma(self._min_gamma, self._max_gamma) \
.vega(self._min_vega, self._max_vega) \
.theta(self._min_theta, self._max_theta) \
.rho(self._min_rho, self._max_rho) \
.implied_volatility(self._min_iv, self._max_iv) \
.open_interest(self._min_open_interest, self._max_open_interest)
# Note: there are also shortcuts for these filter methods:
'''
return universe \View on GitHub (pinned to d2c3659f87)
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.
Example fix
# before: ranges too wide, nothing filtered self._min_delta, self._max_delta = -10.0, 10.0 # after: a range that excludes some contracts self._min_delta, self._max_delta = 0.5, 1.5
Defensive patterns
Strategy: validation
Validate before calling
# Validate the filter actually prunes before returning it
def main_filter(self, universe):
total = len(list(universe))
filtered = self.option_filter(universe)
# option_filter returns an enumerable; materialize once
filtered_list = list(filtered)
if len(filtered_list) >= total and total > 0:
# ranges too wide; log and proceed (or tighten ranges in config)
self.log(f'warning: filter did not reduce universe ({total})')
return filtered_list Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Expected greeks to have valid values. Greeks were: Delta: {g
- Option chain was not received.
- Index is not tradable.
- Trade volume should be greater than zero by the end of this
- Indicators are not ready!
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/29bf65963d828864.
Report an issue: GitHub.