sharpe_ratio was hardcoded to 0.0 in MetricsTracker and exposed as
'or 0' in /api/summary. With only 1 resolved trade (~40 flat days plus
one +299 jump) any computed Sharpe is statistically meaningless, so:
- bot/metrics/sharpe.py: annualized Sharpe (sqrt(365)) from daily
total_pnl closes, normalized by bankroll; sharpe_with_gate() returns
None + status until >=30 days observed AND >=10 resolved trades.
- Database.get_daily_pnl_closes(): last metrics_daily snapshot per UTC
day, oldest first — the return series input.
- MetricsTracker: stores the real (gated) Sharpe in the snapshot, NULL
below the gate; log line now includes sharpe.
- /api/summary: live Sharpe + sharpe_status/days_observed/min_* fields
explaining why it is null; resolved_count now live from COUNT(*).
- promotion_ready: requires resolved>=10, days>=30, and non-null
win_rate/calibration/sharpe plus existing thresholds — a single lucky
resolved trade can no longer promote.
- Dashboard Sharpe card shows the insufficient-sample explanation when
null instead of a bare em dash.
Tests: 13 new in tests/test_sharpe_gate.py (formula, gate, API contract,
tracker snapshot); verified failing pre-fix. Suite: 62 passed.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Shows /api/summary cash_available (now consistent with the executor's cash
model) next to Capital Deployed, with its share of bankroll as subtitle and
progress bar.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Reconstruct dashboard from compiled container: App.jsx, main.jsx, index.css
- nginx.conf with SPA routing and /api proxy to api:8000
- Multi-stage Dockerfile: node:20-alpine build + nginx:alpine serve
- Add third kaniko build step in ci.yml for chemavx/polymarket-bot-dashboard
- Update k8s manifest sed to patch deployment-dashboard.yaml image on each push
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>