Engines
Per-system performance stats and the signal feed that powers the dashboard's engine tabs.
/api/systems
List of every tracked engine plus a summary stats block for each.
// optional since="2025-04-01T00:00:00Z"
{
"systems": ["ultimate_edge", "ew", "gh_lay"],
"stats": {
"ultimate_edge": { "tracked": 412, "win_rate": 22.4, "roi": 8.1 }
}
}
/api/system-stats/<system>
Full stats block for one engine (tracked, wins, losses, ROI, win rate, last signal).
{
"system": "ultimate_edge",
"tracked": 412,
"settled": 398,
"wins": 89,
"losses": 309,
"total_pnl": 142.50,
"roi": 8.1,
"win_rate": 22.4
}
/api/system-pnl/<system>
Cumulative P&L time-series for one engine, ready to plot.
granularity="day" // default since="2025-04-01" // optional
{
"system": "ew",
"granularity": "day",
"points": [
{ "date": "2025-05-01", "daily_pnl": 12.30, "pnl_cumulative": 12.30 }
]
}
/api/system-pnl-all
Bundled P&L series for every engine — one chart, one colour per system.
{
"granularity": "day",
"series": {
"ultimate_edge": [{ "date": "2025-05-01", "pnl_cumulative": 8.40 }],
"gh_lay": [{ "date": "2025-05-01", "pnl_cumulative": 3.10 }]
}
}
/api/signals
Recent signal entries, newest first — feeds the per-system signal table.
system="ew" // optional filter outcome="win" // pending | win | place | lose | void limit=200 // max 2000
{
"count": 2,
"limit": 200,
"entries": [
{ "system": "ew", "selection": "Yachtsman", "odds": 5.5, "outcome": "win", "profit_loss": 4.50 }
]
}
Transparency
ASA-compliant public view of every engine's tracked record — including the losing days.
/api/transparency/summary
Per-engine summary across rolling 30 / 60 / 90 / all-time windows.
{
"systems": ["ew", "gh_lay"],
"stats": {
"ew": {
"tracked": 410, "pending": 3,
"windows": {
"30": { "settled": 42, "roi": 9.1 },
"all": { "settled": 395, "roi": 7.8 }
}
}
},
"disclaimer": "Past performance is not indicative of future results."
}
/api/transparency/timeseries/<system>
Cumulative P&L line over a rolling lookback. Use days=0 for all-time.
days=90 // 30 | 60 | 90 | 365 | 0 (all-time)
{
"system": "ew", "days": 90, "granularity": "day",
"points": [{ "date": "2025-03-01", "pnl_cumulative": 2.10 }]
}
/api/transparency/export/<system>.csv
CSV download of every settled signal for one engine. Columns: date, race, selection, odds, stake, outcome, profit_loss.
/api/transparency/backtest
"What if I'd only taken bets in this odds range" — returns original and filtered curves to overlay.
system="ew" // required min_odds=2.0 max_odds=10.0 days=365 // 0 = all-time
{
"system": "ew", "min_odds": 2.0, "max_odds": 10.0,
"original": { "summary": { "n_settled": 395, "final": 142.50 } },
"filtered": { "summary": { "n_settled": 180, "final": 98.40 } }
}
Bankroll
Per-user bankroll settings + Kelly-recommended stakes for today's active signals.
/api/bankroll/settings
Current bankroll, daily target, Kelly fraction, max stake cap.
{
"settings": {
"bankroll": 1000.0,
"daily_target_pct": 1.5,
"kelly_fraction": 0.25,
"max_stake_pct": 0.02
}
}
/api/bankroll/settings
Update bankroll settings. Values are clamped to safe ranges server-side.
{
"bankroll": 1500,
"daily_target_pct": 1.5,
"kelly_fraction": 0.25,
"max_stake_pct": 0.02
}
{ "ok": true, "settings": { /* normalised */ } }
/api/bankroll/recommendations
Per-active-signal suggested stakes using fractional Kelly. Phrased as "suggested" — never an instruction to bet.
{
"total_signals": 4,
"stakeable_signals": 3,
"total_recommended_stake": 42.50,
"items": [{
"kind": "ultimate_edge", "horse": "Yachtsman", "odds": 5.5,
"stake_recommendation": { "stake": 14.20, "edge_pct": 12.4, "verdict": "stake" }
}]
}
/api/bankroll/summary
Today's P&L versus daily target, intraday drawdown, per-engine breakdown.
{
"target_gbp": 15.00,
"progress_pct": 72.0,
"intraday_pct": 1.08,
"drawdown_warning": false,
"today": { "today_pnl": 10.80, "today_wins": 2, "today_losses": 3 }
}
Pace Map
Per-race pace shape, draw bias, and runner-by-runner verdicts.
/api/pace-map/races
List of every race with a generated pace map (venue, off-time, pace shape).
{
"total": 28,
"races": [{
"idx": 0, "venue": "Ascot", "time": "14:10",
"pace_shape": "LONE_LEADER", "field_size": 10
}]
}
/api/pace-map/<idx>
One race's full pace map — runners with stall, running style, signal verdict, and the pace shape analysis.
{
"summary": { "venue": "Ascot", "pace_shape": "LONE_LEADER" },
"runners": [{
"horse": "Yachtsman", "stall": 4,
"run_style": "LEADER", "combined_score": 82.5,
"signal": "GOLDEN"
}],
"golden_picks": ["Yachtsman"],
"traps": ["Slow Starter"]
}
Leaderboard
Recent settled-signal performance — top winners + per-engine summary over a chosen window.
/api/leaderboard/weekly
7-day leaderboard — alias for /api/leaderboard/7. Used by the landing-page widget.
{
"period_days": 7,
"total_settled": 82, "total_pnl": 38.40,
"overall_win_rate": 26.8,
"per_engine": [{ "system": "ew", "pnl": 22.10, "roi": 11.2 }],
"top_signals": [{ "selection": "Yachtsman", "odds": 5.5, "pnl": 9.0 }]
}
/api/leaderboard/<days>
Same shape as /weekly for any window. Path param is clamped to 1–365 days.
AI Chat
Free-text questions about a single UK race — answered by Claude with race-card context.
/api/race-chat/status
Is AI chat available? Which model? What rate limit applies?
{
"available": true,
"model": "claude-haiku-4-5-20251001",
"rate_limit": { "window_seconds": 3600, "max_questions": 10 }
}
/api/race-chat/races
Today's UK/IRE races available for chat (race_id, course, off_time).
{
"count": 28,
"races": [{ "race_id": "rac_12345", "course": "Ascot", "off_time": "14:10" }]
}
/api/race-chat
Ask one question about one race. Returns analytical commentary — never a tip or instruction.
{
"race_id": "rac_12345",
"question": "Which runner has the strongest data case?",
"session_id": "optional-for-rate-buckets"
}
{
"answer": "The data suggests **Yachtsman** has a strong case...",
"tokens_used": 842,
"model": "claude-haiku-4-5-20251001",
"rate": { "used": 3, "cap": 10 }
}
Push
Web push (PWA) — VAPID-keyed browser notifications for high-EV signals.
/api/push/status
Is web push configured? How many subscriptions are active?
{
"available": true,
"rate_limit_per_hour": 12,
"active_subscriptions": 47,
"vapid_public_present": true
}
/api/push/vapid-public-key
Base64url-encoded VAPID public key. Feed straight to PushManager.subscribe.
{ "public_key": "BNc...wU" }
/api/push/subscribe
Store a browser push subscription. Pass the object returned by PushManager.subscribe.
{
"endpoint": "https://fcm.googleapis.com/fcm/send/...",
"keys": { "p256dh": "BNc...", "auth": "xyz..." }
}
{ "ok": true, "active_subscriptions": 48 }
/api/push/unsubscribe
Remove a subscription by endpoint.
{ "endpoint": "https://fcm.googleapis.com/..." }
/api/push/test
Send a test "ping" notification to every active subscription.
{ "sent": 47, "failed": 0, "dropped": 1 }
Daily morning digest as a low-key alternative to push notifications.
/api/email-digest/status
Is the digest engine running? When does it fire? How many subscribers?
{
"available": true,
"fire_hour_uk": 7,
"active_subscriptions": 23,
"from_addr": "digest@edgepro.local"
}
/api/email-digest/subscribe
Subscribe one email address to the daily digest.
{ "email": "you@example.com" }
/api/email-digest/unsubscribe
Remove an email from the digest list.
{ "email": "you@example.com" }
/api/email-digest/send-test
Send a one-off test digest to a single address. Requires an authenticated session — protects against open-relay abuse.
{ "email": "you@example.com" }
Ops
Operational endpoints — engine heartbeats and pre-launch readiness checks.
/api/health-monitor
Every engine's heartbeat freshness — categorised as healthy / stale / dead / unknown.
max_age=600 // healthy/stale threshold (sec) dead_age=3600 // stale/dead threshold (sec)
{
"counts": { "healthy": 9, "stale": 1, "dead": 0, "unknown": 0 },
"engines": [{
"name": "Each-Way Value", "category": "healthy",
"age_seconds": 42.1, "status": "ok"
}]
}
/api/launch-ready
Pre-launch readiness report — .env, deps, engine compile, heartbeats, data integrity. Pass ?deep=1 to also probe external APIs.
{
"overall": "PASS",
"blocker_count": 0,
"totals": { "pass": 38, "warn": 4, "fail": 0, "skip": 1 },
"sections": { /* one entry per check group */ }
}
No endpoints match your search.