feat(orchestration): nightly runner, rollover budgets, incremental checkpoints

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016DvdRZkyCy9NJpHYDdPqmS
This commit is contained in:
Aryan SinghandClaude Opus 4.8 committed 2026-07-01 16:29:40 -05:00
1 parent b2ae3d6ced
commit aa1ae0c95e
4 files changed
+161

No files matched your search

+43
View File
@@ -0,0 +1,43 @@
"""Time budgeting for the nightly run.
Each agent gets a wall-clock deadline = its fair share of the remaining window, capped by
the per-agent config, and never past the hard stop. If an agent finishes early the freed
time rolls over to those remaining (bounded by the cap), and the hard stop always holds.
"""
from __future__ import annotations
from datetime import datetime, timedelta
from zoneinfo import ZoneInfo
def local_hard_stop_ts(hard_stop_hhmm: str, local_tz: str) -> float:
"""Epoch seconds of the next HH:MM in local time (today if still ahead, else tomorrow)."""
tz = ZoneInfo(local_tz)
now = datetime.now(tz)
hh, mm = (int(x) for x in hard_stop_hhmm.split(":"))
target = now.replace(hour=hh, minute=mm, second=0, microsecond=0)
if target <= now:
target += timedelta(days=1)
return target.timestamp()
def next_deadline(
now_ts: float, hard_stop_ts: float, agents_remaining: int, per_agent_cap_s: float
) -> float:
"""Deadline for the current agent: min(fair share, cap), never past hard stop."""
if agents_remaining <= 0 or now_ts >= hard_stop_ts:
return hard_stop_ts
fair_share = (hard_stop_ts - now_ts) / agents_remaining
span = min(fair_share, per_agent_cap_s) if per_agent_cap_s else fair_share
return now_ts + max(span, 60.0)
def next_market_trade_date(market_tz: str) -> str:
"""Best-effort next trading date (ET), rolling weekends to Monday. Holidays handled in
Phase 3 via Alpaca's calendar; this is only for naming the nightly output folder."""
tz = ZoneInfo(market_tz)
d = datetime.now(tz).date()
while d.weekday() >= 5: # 5 = Sat, 6 = Sun
d += timedelta(days=1)
return d.isoformat()