{"record":{"id":"c04d9acdc6bd4c88","repo":"QuantConnect/Lean","slug":"at-time-es-symbol-is-either-in-regular-hours","errorCode":null,"errorMessage":"At {Time}, {_es.symbol} is either in regular hours but current time is in extended hours, or viceversa","messagePattern":"At (.+?), (.+?) is either in regular hours but current time is in extended hours, or viceversa","errorType":"exception","errorClass":"AssertionError","httpStatus":null,"severity":"error","filePath":"Algorithm.Python/FuturesExtendedMarketHoursRegressionAlgorithm.py","lineNumber":59,"sourceCode":"        slice_symbols.update([x.canonical for x in slice_symbols])\n\n        es_is_in_regular_hours = self._es.exchange.hours.is_open(self.time, False)\n        es_is_in_extended_hours = not es_is_in_regular_hours and self._es.exchange.hours.is_open(self.time, True)\n        slice_has_e_s_data = self._es.symbol in slice_symbols\n        self._es_ran_on_regular_hours |= es_is_in_regular_hours and slice_has_e_s_data\n        self._es_ran_on_extended_hours |= es_is_in_extended_hours and slice_has_e_s_data\n\n        gc_is_in_regular_hours = self._gc.exchange.hours.is_open(self.time, False)\n        gc_is_in_extended_hours = not gc_is_in_regular_hours and self._gc.exchange.hours.is_open(self.time, True)\n        slice_has_g_c_data = self._gc.symbol in slice_symbols\n        self._gc_ran_on_regular_hours |= gc_is_in_regular_hours and slice_has_g_c_data\n        self._gc_ran_on_extended_hours |= gc_is_in_extended_hours and slice_has_g_c_data\n\n        time_of_day = self.time.time()\n        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))\n        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))\n        if es_is_in_regular_hours != current_time_is_regular_hours or es_is_in_extended_hours != current_time_is_extended_hours:\n            raise AssertionError(\"At {Time}, {_es.symbol} is either in regular hours but current time is in extended hours, or viceversa\")\n\n    def on_end_of_algorithm(self):\n        if not self._es_ran_on_regular_hours:\n            raise AssertionError(f\"Algorithm should have run on regular hours for {self._es.symbol} future, which enabled extended market hours\")\n\n        if not self._es_ran_on_extended_hours:\n            raise AssertionError(f\"Algorithm should have run on extended hours for {self._es.symbol} future, which enabled extended market hours\")\n\n        if not self._gc_ran_on_regular_hours:\n            raise AssertionError(f\"Algorithm should have run on regular hours for {self._gc.symbol} future, which did not enable extended market hours\")\n\n        if self._gc_ran_on_extended_hours:\n            raise AssertionError(f\"Algorithm should have not run on extended hours for {self._gc.symbol} future, which did not enable extended market hours\")\n","sourceCodeStart":41,"sourceCodeEnd":73,"githubUrl":"https://github.com/QuantConnect/Lean/blob/d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892/Algorithm.Python/FuturesExtendedMarketHoursRegressionAlgorithm.py#L41-L73","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Print self.time (with tz), es_is_in_regular_hours, and current_time_is_regular_hours to find the disagreement.","Cross-check the MarketHoursDatabase entry for ES against the hard-coded windows.","Update the hard-coded time windows if CME hours legitimately changed.","Ensure self.time is in the timezone the hard-coded windows assume."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"# Cross-check engine hours classification vs clock-time windows\ntod = self.time.time()\nreg = (time(9,30) <= tod < time(16,15)) or (time(16,30) <= tod < time(17,0))\next = not reg and (tod < time(9,30) or tod >= time(18,0))\nif self._es.exchange.hours.is_open(self.time, False) != reg:\n    self.debug(f\"Hours DB disagrees with clock-time regular window at {self.time}\")","typeGuard":"def engine_matches_clock_window(security, t: datetime) -> bool:\n    tod = t.time()\n    reg = (time(9,30) <= tod < time(16,15)) or (time(16,30) <= tod < time(17,0))\n    return security.exchange.hours.is_open(t, False) == reg","tryCatchPattern":null,"preventionTips":["Keep the hard-coded session windows in sync with MarketHoursDatabase.","Compare self.time and is_open output in the same timezone.","Log disagreements before raising.","Update windows when CME session definitions change."],"tags":["quantconnect","futures","extended-market-hours","market-hours-database","timezone","regression-test"],"backgroundTag":null,"analyzedSha":"d2c3659f877bfc2b5d9dc0fc89a9c7566f45e892","analyzedAt":"2026-08-13T13:52:21.013Z","schemaVersion":2},"datasetVersion":"2026-08-13T14:17:21.547Z"}