fix(crypto): daily cron reliability — once-per-UTC-day guard + daytime multi-attempt

Nighttime cron (01:17 UTC) silently never fired: workstation suspends at night and standard
cron does not catch up missed jobs on wake (uptime hides suspend). Fix: (1) idempotent
once-per-UTC-day guard in 'run' (last_run_date in state) so multiple attempts cannot double-book;
(2) cron now fires at 09:10/12:10/15:10/18:10 UTC daily -> first attempt while the machine is
awake books the day, the rest no-op. Robust to the machine being off at any single slot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
jgrusewski
2026-06-07 09:35:46 +02:00
parent 42e9621c47
commit 24ac921cd3

View File

@@ -115,6 +115,10 @@ def cmd_snapshot():
def cmd_run():
st = load_state()
today = datetime.datetime.now(datetime.timezone.utc).date().isoformat()
if st.get("last_run_date") == today: # idempotent: one booking per UTC day
print(f"already booked {today} (day {st['days']}); skipping")
return
prev = st["positions"]
liq, tf30, last24 = scan(prev)
realized = sum(w * last24.get(c, 0.0) for c, w in prev.items())
@@ -123,7 +127,7 @@ def cmd_run():
newpos = {c: 1.0 / n for c in q} if n else {}
turnover = sum(abs(newpos.get(c, 0) - prev.get(c, 0)) for c in set(newpos) | set(prev))
net = realized - turnover * (COST_RT / 2)
st.update(positions=newpos, days=st["days"] + 1)
st.update(positions=newpos, days=st["days"] + 1, last_run_date=today)
st["cum_gross"] += realized
st["cum_net"] += net
os.makedirs(os.path.dirname(STATE), exist_ok=True)