QuantConnect/Lean · error · AssertionError

At {Time}, {_es.symbol} is either in regular hours but curre

Error message

At {Time}, {_es.symbol} is either in regular hours but current time is in extended hours, or viceversa

What it means

Intraday hours-consistency assertion in an extended-market-hours regression. For the ES future (extended hours enabled) the test computes whether the engine considers the time regular vs extended (via exchange.hours.is_open) and compares against a hard-coded clock-time breakdown of the CME session. Any disagreement aborts.

Source

Thrown at Algorithm.Python/FuturesExtendedMarketHoursRegressionAlgorithm.py:59

        slice_symbols.update([x.canonical for x in slice_symbols])

        es_is_in_regular_hours = self._es.exchange.hours.is_open(self.time, False)
        es_is_in_extended_hours = not es_is_in_regular_hours and self._es.exchange.hours.is_open(self.time, True)
        slice_has_e_s_data = self._es.symbol in slice_symbols
        self._es_ran_on_regular_hours |= es_is_in_regular_hours and slice_has_e_s_data
        self._es_ran_on_extended_hours |= es_is_in_extended_hours and slice_has_e_s_data

        gc_is_in_regular_hours = self._gc.exchange.hours.is_open(self.time, False)
        gc_is_in_extended_hours = not gc_is_in_regular_hours and self._gc.exchange.hours.is_open(self.time, True)
        slice_has_g_c_data = self._gc.symbol in slice_symbols
        self._gc_ran_on_regular_hours |= gc_is_in_regular_hours and slice_has_g_c_data
        self._gc_ran_on_extended_hours |= gc_is_in_extended_hours and slice_has_g_c_data

        time_of_day = self.time.time()
        current_time_is_regular_hours = (time_of_day >= time(9, 30, 0) and time_of_day < time(16, 15, 0)) or (time_of_day >= time(16, 30, 0) and time_of_day < time(17, 0, 0))
        current_time_is_extended_hours = not current_time_is_regular_hours and (time_of_day < time(9, 30, 0) or time_of_day >= time(18, 0, 0))
        if es_is_in_regular_hours != current_time_is_regular_hours or es_is_in_extended_hours != current_time_is_extended_hours:
            raise AssertionError("At {Time}, {_es.symbol} is either in regular hours but current time is in extended hours, or viceversa")

    def on_end_of_algorithm(self):
        if not self._es_ran_on_regular_hours:
            raise AssertionError(f"Algorithm should have run on regular hours for {self._es.symbol} future, which enabled extended market hours")

        if not self._es_ran_on_extended_hours:
            raise AssertionError(f"Algorithm should have run on extended hours for {self._es.symbol} future, which enabled extended market hours")

        if not self._gc_ran_on_regular_hours:
            raise AssertionError(f"Algorithm should have run on regular hours for {self._gc.symbol} future, which did not enable extended market hours")

        if self._gc_ran_on_extended_hours:
            raise AssertionError(f"Algorithm should have not run on extended hours for {self._gc.symbol} future, which did not enable extended market hours")

View on GitHub (pinned to d2c3659f87)

Solutions

  1. Print self.time (with tz), es_is_in_regular_hours, and current_time_is_regular_hours to find the disagreement.
  2. Cross-check the MarketHoursDatabase entry for ES against the hard-coded windows.
  3. Update the hard-coded time windows if CME hours legitimately changed.
  4. Ensure self.time is in the timezone the hard-coded windows assume.
Defensive patterns

Strategy: validation

Validate before calling

# Cross-check engine hours classification vs clock-time windows
tod = self.time.time()
reg = (time(9,30) <= tod < time(16,15)) or (time(16,30) <= tod < time(17,0))
ext = not reg and (tod < time(9,30) or tod >= time(18,0))
if self._es.exchange.hours.is_open(self.time, False) != reg:
    self.debug(f"Hours DB disagrees with clock-time regular window at {self.time}")

Type guard

def engine_matches_clock_window(security, t: datetime) -> bool:
    tod = t.time()
    reg = (time(9,30) <= tod < time(16,15)) or (time(16,30) <= tod < time(17,0))
    return security.exchange.hours.is_open(t, False) == reg

Prevention

When it happens

Trigger: MarketHoursDatabase entry for CME ES disagreeing with the hard-coded 09:30-16:15 / 16:30-17:00 / pre-09:30 / post-18:00 windows; self.time timezone differing from the hard-coded times; engine changes to is_open semantics.

Common situations: Updates to MarketHoursDatabase that shift the ES session boundaries; timezone handling changes; new fill-forward behaviour crossing session edges; the hard-coded window being stale relative to current CME hours.

Related errors


AI-assisted analysis of QuantConnect/Lean@d2c3659f87 (2026-08-13). Data as JSON: /api/errors/c04d9acdc6bd4c88. Report an issue: GitHub.