From 6dac8a2c7f44776cee2f33fad891231474671e9a Mon Sep 17 00:00:00 2001 From: Giorgio Gilestro Date: Sat, 16 May 2026 10:20:05 +0100 Subject: [PATCH] cadence: support multiple active windows; Asia window commented out MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refactored CadencePolicy.active_start_hour/active_end_hour into a tuple of (start, end) hour pairs so additional regional windows can be added without code changes. Default keeps EU/US-only behaviour identical. The Asia window (00:00-08:00 UTC — Tokyo + HK + Shanghai) is included as a commented-out tuple in the dataclass default. Uncomment one line to enable hourly AI cadence during the Asia session as well. Co-Authored-By: Claude Opus 4.7 (1M context) --- app/services/cadence.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/app/services/cadence.py b/app/services/cadence.py index 866b4c9..b3c6127 100644 --- a/app/services/cadence.py +++ b/app/services/cadence.py @@ -18,11 +18,17 @@ from datetime import datetime, timezone @dataclass(frozen=True) class CadencePolicy: - # Active window in UTC. LSE opens 07:00 BST → 07:00 UTC summer, 08:00 UTC - # winter. NYSE closes 16:00 ET → 21:00 UTC summer, 21:00 UTC winter. The - # combined EU/US trading window is well covered by 07:00-21:00 UTC. - active_start_hour: int = 7 - active_end_hour: int = 21 + # Active trading windows in UTC. A timestamp is "active" if its hour + # falls in ANY listed window. Add or remove tuples to change coverage. + # + # LSE opens 07:00 BST → 07:00 UTC summer / 08:00 UTC winter. + # NYSE closes 16:00 ET → 21:00 UTC summer / 21:00 UTC winter. + # Tokyo trades 09:00-15:00 JST → 00:00-06:00 UTC. + # HK/Shanghai trade 09:30-16:00 local → 01:30-08:00 UTC. + active_windows: tuple[tuple[int, int], ...] = ( + (7, 21), # EU/US (LSE open through NYSE close) + # (0, 8), # Asia (Tokyo + HK/Shanghai) — uncomment to add + ) # Minimum gap between successful runs outside the active window. off_hours_gap_h: float = 4.0 weekend_gap_h: float = 12.0 @@ -31,7 +37,7 @@ class CadencePolicy: now = now or datetime.now(timezone.utc) if now.weekday() >= 5: # Saturday / Sunday return False - return self.active_start_hour <= now.hour < self.active_end_hour + return any(start <= now.hour < end for start, end in self.active_windows) def min_gap_hours(self, now: datetime | None = None) -> float: now = now or datetime.now(timezone.utc)