Bivariate Poisson
The Oracle
Every football match is two Poisson processes wearing team shirts. Dixon & Coles (1997) showed how to estimate their rates — and how to fix the model's one systematic lie about low-scoring draws. Pick any fixture in Europe's big five and this engine prices it live: El Clásico at the Camp Nou comes out 55 / 20 / 26.
The matchup oracle
Pick a league, a home side and an away side. The page computes the scoring rates λ (home) and μ (away) from the fitted ratings, builds the full score matrix with the Dixon–Coles low-score correction, and reads off the odds — all client-side, from the same ~40 parameters per league (two per team, plus a league intercept, home advantage and ρ) the model actually learned. The goals model was trained on what happened; the xG blend on what deserved to happen (85% xG, 15% goals).
Score probability matrix
P(exact scoreline), % · rows = home goals, columns = away goals
Match odds (1X2)
probability of home win / draw / away win, %
Five most likely scorelines
home–away · % of all outcomes
Ratings are frozen at each league's final 2025/26 matchday (2026-05-16 to 2026-05-24); the oracle prices a hypothetical fixture played then.1 Team names follow Understat spellings.
Every team, reduced to two numbers
Under the hood each team is just an attack rating and a defence rating on the log scale. Exponentiate them against a league-average opponent at a neutral venue and you get something legible: expected goals scored and conceded per match. Plotted together, the league sorts itself into quadrants — and the outliers write the season's story. Bayern Munich sit further from the pack than any side in Europe at +1.86 expected goal difference per match (3.00 scored, 1.14 conceded); PSG (+1.44), Barcelona (+1.43) and Inter (+1.30) rule their islands, while Arsenal (+1.23) hold off Manchester City (+1.04) on defence, not attack.
Attack vs defence, xG-blend ratings
expected goals for and against per match vs a league-average opponent, neutral venue · up = meaner defence · axes fixed across leagues
| Team | xG for / match | xG against / match | Strength (diff) | Finishing Δ |
|---|
Finishing Δ is the gap between the goals-model attack rating and the xG-blend attack rating: positive means the side has been scoring above what its chances predict. Pisa (−0.31) and Real Oviedo (−0.29) are the biggest underperformers in Europe; Bayern (+0.15) the biggest overperformer.
The τ correction: fixing the model's one lie
Two independent Poisson processes underestimate how often football produces 0–0 and 1–1, and overestimate 1–0 and 0–1. Dixon and Coles patched exactly those four cells with a single dependence parameter ρ, leaving the rest of the matrix untouched. Our fits reproduce their 1997 finding: ρ comes out negative in four of five leagues — Premier League −0.102, Bundesliga −0.071, Ligue 1 −0.046, Serie A −0.033 — which raises the goalless and 1–1 draws. La Liga is the mild exception at +0.012, essentially independence.
Drag ρ and watch the four cells move. Everything else only shifts through renormalisation.
Independent Poisson
P(scoreline), % · scores 0–3 shown
With the τ correction
P(scoreline), % · scores 0–3 shown
What moved
τ multiplies P(0,0) by 1 − λμρ, P(0,1) by 1 + λρ, P(1,0) by 1 + μρ and P(1,1) by 1 − ρ. The slider stays inside the validity range max(−1/λ, −1/μ) ≤ ρ ≤ min(1/λμ, 1).
Tuning: how fast to forget, how much to trust xG
Old matches lie about current strength, so each match is down-weighted by e^(−ξ·days). But ξ can't be estimated by maximum likelihood — a bigger ξ always "fits" recent data better — so it is grid-searched on out-of-sample forecast skill over an 828-match validation window. The curve bottoms out at ξ* = 0.002 per day: a match from 347 days ago counts half as much. That lands dead-centre of the 0.0018–0.0033/day range modern Dixon–Coles replications report.
The same protocol chooses how much of the training target should be xG rather than goals. The answer: most of it. w* = 0.85 edges out every alternative, beating the pure-goals target on validation RPS 0.20066 vs 0.20276 — finishing luck, integrated out.
The memory curve: skill vs decay rate ξ
validation RPS (lower = better) · y-axis zoomed to the decision band
The trust curve: skill vs xG share w
validation RPS (lower = better) · target g* = w·xG + (1−w)·goals
The honesty table
A forecaster earns its keep out of sample. Protocol: rolling-origin backtest over each league's final 60 days — refit before every matchweek on all prior matches (time-decayed), predict that week, score it, move on. 385 matches, never seen at fit time. Both models beat both naive baselines by 9–11% on RPS — squarely in the 0.19–0.21 band the literature calls a good Dixon–Coles fit. The fine print: on this holdout the goals model (0.2097) and the xG blend (0.2101) are statistically tied, even though validation preferred the blend. Honest models keep both numbers on the table.
Pooled holdout skill: model vs baselines
ranked probability score, lower = better · n = 385 matches, spring 2026
- Dixon–Coles models
- Naive baselines
| League | n | Goals RPS | xG-blend RPS | Base-rate RPS | Uniform RPS | Goals log-loss | xG-blend log-loss |
|---|
RPS treats a draw as "closer" to a home win than an away win is. Wheatcroft (2021) argues that ordinality premise is shaky and log-loss suffices — so both are reported; the ranking of models is the same under either.2
1 Reference dates: EPL, La Liga, Serie A 2026-05-24; Ligue 1 2026-05-17; Bundesliga 2026-05-16. 2 Wheatcroft, E. (2021), JQAS. Full derivations in the research brief: Dixon & Coles (1997), Karlis & Ntzoufras (2003) for the bivariate extension, Ley et al. (2019) for the half-life reparametrisation.