Prediction methodology
How we generate, settle, and read our predictions.
How predictions are generated
- Moneyline (Elo) — Two teams' Elo ratings feed the standard win-probability formula. The K-factor controls per-game volatility:
P(A wins) = 1 / (1 + 10^((R_B − R_A) / 400)) - Total (Poisson) — Each team's finished-game scoring mean becomes its λ; we sum two Poisson distributions to project the total:
projected_total = Σ Poisson(λ_team) for each team's finished-event mean - The generate-predictions cron runs hourly, scans events scheduled in the next 6 hours, writes the prediction row, and timestamps generated_at — predictions are committed before kickoff.
Settlement rules
- Moneyline — After an event reaches status='finished', we compare score_json.winner against pick.side — same side = hit, opposite side = miss.
- Total — We compute actual_total = home_score + away_score, then store abs_error and signed_error vs projected_total. The outcome is labelled scored (not hit / miss — it's a continuous metric, not a binary call).
- Voided — If the event ends up postponed or cancelled, the prediction is voided and excluded from both win-rate and MAE aggregates.
How to read the numbers
- When total settlements are below 30, the win-rate / MAE cell renders 'Sample too small' instead of a number — the law of large numbers needs time to kick in.
- Confidence is the model's own belief in the prediction, not market or community confidence. A well-calibrated model wins 70% of the games it labelled 70% — we visualize this on the calibration chart on the track-record page.
- projected − actual
Every prediction is locked once generated_at is written. Historical pages remain readable; commit history is public on git.