Phase 2: predictive model — Elo + Dixon-Coles + Monte Carlo

- buildRatings.ts: walks 49k historical results → World-Football-Elo per team,
  data-calibrated goals model (goals-per-Elo slope, mean goals) + MLE-fit
  Dixon-Coles rho. Top: Spain/Argentina/France (the real 2026 favourites)
- src/lib/model: elo, poisson/dixon-coles, predict, host-advantage, monteCarlo
  (full 48-team sim — group sampling, best-third bipartite allocation, knockout
  advance probs). 20 vitest cases incl. exact per-round count invariants
- Server ModelEngine: live Elo re-rating after each result, per-match W/D/L,
  20k-sim odds, odds-over-time history; broadcast on finished-result changes
- Client: championship board, heat-shaded odds table, lazy-loaded title-race
  chart (Recharts split to its own chunk), match-prediction bars, bracket
  advance overlay
- Verified: odds render, chart populates as injected results re-rate teams live

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-11 13:25:53 +02:00
parent 9a31e9f4db
commit d604bb14ff
19 changed files with 1263 additions and 21 deletions
+5
View File
@@ -63,6 +63,11 @@ export class TournamentState {
return this.byNum.get(num);
}
/** The live fixtures array (for the model engine). */
allFixtures(): Fixture[] {
return this.fixtures;
}
/** True if any match is live or kicks off within `windowMs` of now — used to
* poll the APIs often during match windows and rarely when nothing is on. */
hasLiveActivity(windowMs: number): boolean {