QuantConnect/Lean · error · AssertionError
Expected 4 delisting events received, found: {self.delisting
Error message
Expected 4 delisting events received, found: {self.delistings_received} What it means
Asserts exactly 4 delisting events were received (warning + delisted for the future, warning + delisted for the FOP). delistings_received is incremented per delisting object in data.delistings; any other count aborts.
Source
Thrown at Algorithm.Python/FuturesAndFuturesOptionsExpiryTimeAndLiquidationRegressionAlgorithm.py:99
# * Future Liquidation
# * Future Option Exercise
# * We expect NO Underlying Future Liquidation because we already hold a Long future position so the FOP Put selling leaves us breakeven
self.liquidated += 1
if order_event.symbol.security_type == SecurityType.FUTURE_OPTION and self.expected_liquidation_time != self.time:
raise AssertionError(f"Expected to liquidate option {order_event.symbol} at {self.expected_liquidation_time}, instead liquidated at {self.time}")
if order_event.symbol.security_type == SecurityType.FUTURE and \
(self.expected_liquidation_time - timedelta(minutes=1)) != self.time and \
self.expected_liquidation_time != self.time:
raise AssertionError(f"Expected to liquidate future {order_event.symbol} at {self.expected_liquidation_time} (+1 minute), instead liquidated at {self.time}")
def on_end_of_algorithm(self):
if not self.invested:
raise AssertionError("Never invested in ES futures and FOPs")
if self.delistings_received != 4:
raise AssertionError(f"Expected 4 delisting events received, found: {self.delistings_received}")
if self.liquidated != 2:
raise AssertionError(f"Expected 3 liquidation events, found {self.liquidated}")
View on GitHub (pinned to d2c3659f87)
Solutions
- Log every delisting received (symbol + type + time) to see which are missing/extra.
- Verify both the future and FOP data files contain delisting metadata.
- Update the expected count if the engine's delisting-event semantics intentionally changed.
- Filter out canonical-symbol delistings if they are now double-counted.
Defensive patterns
Strategy: validation
Validate before calling
# Track delisting events with detail
seen = []
for d in data.delistings.values():
seen.append((d.symbol, d.type, d.time))
if len(seen) != 4:
self.debug(f"Delisting count {len(seen)} != 4: {seen}") Type guard
def delisting_count_is(data, expected: int) -> bool:
return len(list(data.delistings.values())) == expected Prevention
- Log every delisting (symbol + type + time) when debugging.
- Verify both contracts' data files contain delisting metadata.
- Filter canonical duplicates if double-counting appears.
- Re-baseline the count after engine delisting-emission changes.
When it happens
Trigger: Engine emitting duplicate or missing delisting events; only one of the two contracts getting delisted; data refreshes removing/adding delisting notices.
Common situations: Engine changes to delisting emission count; data issues suppressing a delisting event; symbol-mapping producing extra canonical delistings.
Related errors
- [{UtcTime}] We hold a delisted securities: {string.Join(",",
- 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
- Delisting notice received at an unexpected date: {self.time}
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/9dab2bb1bb213bf6.
Report an issue: GitHub.