QuantConnect/Lean · error · AssertionError
The Exchange hours was closed, verify 'extended_market_hours
Error message
The Exchange hours was closed, verify 'extended_market_hours' flag in Initialize() when added new security(ies)
What it means
Assertion in on_order_event of a future stop-market-order regression. After a STOP_MARKET order fills, the test fetches the security's exchange-hours entry from market_hours_database and calls is_open(order_event.utc_time, is_extended_market_hours). If the fill timestamp falls outside the declared open session the test aborts. Its purpose is to prove the extended_market_hours=True flag on add_future actually allowed fills in extended hours.
Source
Thrown at Algorithm.Python/FutureStopMarketOrderOnExtendedHoursRegressionAlgorithm.py:63
def on_data(self, slice: Slice) -> None:
if (self._stop_market_ticket == None or self._stop_market_ticket.status != OrderStatus.SUBMITTED):
return None
self.stop_price = self._stop_market_ticket.get(OrderField.STOP_PRICE)
self.bar = self.securities[self._stop_market_ticket.symbol].cache.get_data()
# An order fill update the resulting information is passed to this method.
def on_order_event(self, order_event: OrderEvent) -> None:
if self.transactions.get_order_by_id(order_event.order_id).type is not OrderType.STOP_MARKET:
return None
if order_event.status == OrderStatus.FILLED:
# Get Exchange Hours for specific security
exchange_hours = self.market_hours_database.get_exchange_hours(self._sp_500_e_mini.subscription_data_config)
# Validate, Exchange is opened explicitly
if (not exchange_hours.is_open(order_event.utc_time, self._sp_500_e_mini.is_extended_market_hours)):
raise AssertionError("The Exchange hours was closed, verify 'extended_market_hours' flag in Initialize() when added new security(ies)")
def on_end_of_algorithm(self) -> None:
self.stop_market_orders = self.transactions.get_orders(lambda o: o.type is OrderType.STOP_MARKET)
for o in self.stop_market_orders:
if o.status != OrderStatus.FILLED:
raise AssertionError("The Algorithms was not handled any StopMarketOrders")
View on GitHub (pinned to d2c3659f87)
Solutions
- Ensure add_future(..., extended_market_hours=True) is set for the security whose fills are asserted.
- Check the MarketHoursDatabase entry for the symbol's market (CME) covers the extended hours window containing order_event.utc_time.
- Log order_event.utc_time and the exchange_hours output to confirm whether the gap is real or a TZ bug.
- If the database entry changed intentionally, update the regression's expected fill window rather than the assertion.
Example fix
// before self._sp_500_e_mini = self.add_future(Futures.Indices.SP_500_E_MINI, Resolution.MINUTE) // after self._sp_500_e_mini = self.add_future(Futures.Indices.SP_500_E_MINI, Resolution.MINUTE, extended_market_hours=True)
Defensive patterns
Strategy: validation
Validate before calling
# Pre-check exchange hours before asserting on a fill
exchange_hours = self.market_hours_database.get_exchange_hours(
self._sp_500_e_mini.subscription_data_config)
if not exchange_hours.is_open(order_event.utc_time, self._sp_500_e_mini.is_extended_market_hours):
self.debug(f"Fill at {order_event.utc_time} outside open session; investigate hours DB") Type guard
def is_fill_session_open(mhdb, security, utc_time: datetime) -> bool:
eh = mhdb.get_exchange_hours(security.subscription_data_config)
return eh.is_open(utc_time, security.is_extended_market_hours) Prevention
- Always pass extended_market_hours=True to add_future when extended fills are expected.
- Cross-check the MarketHoursDatabase entry for the symbol's market.
- Log order_event.utc_time alongside is_open results when debugging.
- Normalize timezones before comparing fill time against session windows.
When it happens
Trigger: A stop-market fill whose utc_time lands in a session gap; extended_market_hours being False (or defaulting) while the test expects extended-hours fills; a market_hours_database entry for the ES CME future that does not mark the extended window as open; fill timestamp timezone/mapping drift.
Common situations: Forgetting to pass extended_market_hours=True in add_future; updating MarketHoursDatabase entries for CME that narrow the extended session; data-driven fills landing exactly on a session boundary that is_open treats as closed; timezone handling changes in the engine.
Related errors
- At {Time}, {_es.symbol} is either in regular hours but curre
- The Algorithms was not handled any StopMarketOrders
- Algorithm should have run on regular hours for {self._es.sym
- Algorithm should have run on extended hours for {self._es.sy
- [{UtcTime}] We hold a delisted securities: {string.Join(",",
AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13).
Data as JSON: /api/errors/7b57502d8cf56def.
Report an issue: GitHub.