diff --git a/api/static/dashboard.html b/api/static/dashboard.html index 412bb90..a65b58d 100644 --- a/api/static/dashboard.html +++ b/api/static/dashboard.html @@ -471,7 +471,8 @@ function render(d) { $("risk-day").textContent = rk.day_pnl_pct != null ? (rk.day_pnl_pct * 100).toFixed(1) + "% / -" + (rk.daily_loss_limit_pct * 100).toFixed(0) + "%" : "—"; const fr = $("risk-fresh"); fr.textContent = rk.data_age_s != null ? rk.data_age_s.toFixed(0) + "s" : "—"; - fr.style.color = (rk.data_age_s == null) ? "" : (rk.data_age_s > 90 ? "#ff4d4f" : rk.data_age_s > 30 ? "#f1c40f" : ""); + // broker sync runs ~every 60s, so >90s = a missed sync (amber), >180s = stale (red) + fr.style.color = (rk.data_age_s == null) ? "" : (rk.data_age_s > 180 ? "#ff4d4f" : rk.data_age_s > 90 ? "#f1c40f" : ""); const accts = d.accounts || []; $("acct-count").textContent = accts.length; diff --git a/storage/projections.py b/storage/projections.py index 9079314..941368a 100644 --- a/storage/projections.py +++ b/storage/projections.py @@ -625,8 +625,12 @@ def query_risk_state(store) -> dict: t = (datetime.fromisoformat(ts_latest.replace("Z", "+00:00")) if isinstance(ts_latest, str) else ts_latest) if t.tzinfo is None: - t = t.replace(tzinfo=timezone.utc) - age = (datetime.now(timezone.utc) - t).total_seconds() + # event timestamps are stored NAIVE LOCAL (datetime.now()), so + # compare against naive-local now — comparing to UTC would be off + # by the whole timezone offset (the chip read ~4h on fresh data). + age = (datetime.now() - t).total_seconds() + else: + age = (datetime.now(timezone.utc) - t).total_seconds() except Exception: # noqa: BLE001 pass