WC26 Dashboard: Live World Cup Pool Forecasting
Shows each of 5 quiniela players their live odds of winning the pool, updated on every real match result; with a what-if builder for any hypothetical.
10,000 runs of the full 104-match tournament in under 3 s; odds cached in Cosmos by completed-match count so they serve instantly between real matches and always refresh when one lands.
Situation
Five of us run a World Cup quiniela: each picks five teams from a hat out of the best 25 we think could win, and whoever’s teams wins the world cup, wins the pool. Everyone wanted to know their live odds, and there was no public, inspectable model that updates as the real tournament unfolds.
Task
Build and ship a live dashboard that, as real results come in, gives each player their probability of finishing 1st–5th in the pool, and lets anyone explore what-if scenarios.
Action
- Built a pure, seedable simulation engine: a standard Elo win-probability drives a Monte Carlo over every remaining match, run 10,000× to tally each player’s finish distribution. It imports no cloud or IO, and a contract test fails the build if it ever does.
- Wrapped the engine in a Python Azure Functions handler with a Cosmos DB cache keyed by the completed-match count: baseline results are served instantly from the cache; a scenario override always recomputes fresh and is never cached.
- A timer-triggered job pulls live results from a sports API and updates team Elo ratings (K=32) after each match. The front end is a static-exported Next.js app on Azure Static Web Apps, bilingual es/en, with a scenario builder that lets anyone fix a hypothetical result and watch the pool odds shift.
How it works
A pure simulation engine (Elo logistic + Monte Carlo, importing no cloud) behind a Python Azure Functions API, with a Cosmos cache keyed by tournament progress and a timer job that live-updates Elo from a sports feed. The front end is a static-exported Next.js app on Azure SWA.
Result
Live in three days from conception and serving a real World Cup pool: a Next.js + Azure Functions app with 116 tests across 9 files, green on every CI push. The pure engine simulates the full 104-match tournament 10,000× in under 3 seconds (a bound enforced on every CI run), so baseline odds are cached in Cosmos and recomputed only when a real match finishes, while scenario what-ifs run fresh.
Learning
The value here was never model sophistication: a 400-point Elo logistic with a flat draw rate is the whole match model. It was engineering the boundary: a pure, seedable, dependency-free simulation engine wrapped in a serverless handler that caches by real-world state and recomputes only for hypotheticals. The artifact I'm proudest of is the contract test that fails the build if the word "azure" ever appears in the engine. It keeps the model something you can test and reason about offline, no cloud attached.
Tech Stack
Services
Status
Live