Model
Tennis: how well the predictions actually do, and what they were built from
Is the model any good?
Backtests
| Model | Matches | Log loss | Baseline | Edge | Brier | Accuracy | Settings | Run |
|---|---|---|---|---|---|---|---|---|
| serve-hold-oos | 2647 | 0.6473 | 0.6930 | +0.0457 | 0.4550 | 62.8% | WTA | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.54 (naive 5.16) | total MAE 5.15 (naive 4.89) | 4 Sep 10:06 |
| serve-hold-oos | 1523 | 0.6575 | 0.6938 | +0.0363 | 0.4639 | 62.5% | ATP | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.44 (naive 4.82) | total MAE 7.05 (naive 7.03) | 4 Sep 10:04 |
| serve-hold-oos | 2816 | 0.6506 | 0.6937 | +0.0431 | 0.4586 | 62.8% | WTA | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.55 (naive 5.15) | total MAE 5.13 (naive 4.86) | 4 Sep 09:48 |
| serve-hold-oos | 1718 | 0.6624 | 0.6937 | +0.0313 | 0.4683 | 61.8% | ATP | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.41 (naive 4.77) | total MAE 6.86 (naive 6.86) | 4 Sep 09:33 |
| serve-hold-oos | 2647 | 0.6473 | 0.6930 | +0.0457 | 0.4550 | 62.8% | WTA | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.54 (naive 5.16) | total MAE 5.15 (naive 4.89) | 4 Sep 09:18 |
| serve-hold-oos | 1523 | 0.6575 | 0.6938 | +0.0363 | 0.4639 | 62.5% | ATP | sport=tennis target=xg xi=0.003 reg=1.0 step=150 | margin MAE 4.46 (naive 4.82) | total MAE 7.05 (naive 7.03) | 4 Sep 09:09 |
Log loss is the average negative log probability the model gave to what actually happened — lower is better. Baseline is the same score for a model that always predicts the league's base rate of home/draw/away, and edge is how much the model beats it by. An edge at or below zero means the model has learned nothing worth having.
Stored predictions
| Model | Predictions | On upcoming fixtures | Generated |
|---|---|---|---|
| deep | 1 | 1 | 4 Sep 2026 10:14 |
| serve-hold-oos | 4554 | 0 | 4 Sep 2026 10:06 |
| serve-hold | 33 | 33 | 4 Sep 2026 10:04 |
Data behind it
Covering 2026-01-02 to 2026-09-05.
Source: Understat, via the soccerdata scraper.
Calibration
When the model claimed a probability in each band, how often was it actually right? A negative gap means overconfidence — the model promises more than it delivers, and every pick in that band is marked down before it is ranked. Bands with fewer than 60 past results are hidden as too thin to read anything into.
| Market | Band | Claimed | Actually won | Gap | Sample | |
|---|---|---|---|---|---|---|
| Deciding set | 35%–40% | 37.8% | 34.9% | -2.9 | 324 | |
| Deciding set | 40%–45% | 42.8% | 37.4% | -5.4 | 732 | |
| Deciding set | 45%–50% | 48.6% | 39.0% | -9.6 | 3147 | |
| Deciding set | 50%–55% | 51.4% | 56.9% | +5.5 | 3147 | |
| Deciding set | 55%–60% | 57.2% | 56.8% | -0.3 | 732 | |
| Deciding set | 60%–65% | 62.2% | 62.3% | +0.1 | 324 | |
| Deciding set | 65%–70% | 67.2% | 68.9% | +1.7 | 167 | |
| Deciding set | 70%–75% | 72.1% | 67.1% | -5.0 | 85 | |
| Deciding set | 75%–80% | 77.5% | 66.7% | -10.9 | 63 | |
| First set | 35%–40% | 37.7% | 42.1% | +4.4 | 805 | |
| First set | 40%–45% | 42.6% | 42.3% | -0.4 | 1055 | |
| First set | 45%–50% | 47.5% | 49.5% | +2.0 | 1159 | |
| First set | 50%–55% | 52.5% | 50.5% | -2.0 | 1159 | |
| First set | 55%–60% | 57.4% | 57.7% | +0.4 | 1055 | |
| First set | 60%–65% | 62.3% | 57.9% | -4.4 | 805 | |
| First set | 65%–70% | 67.3% | 57.1% | -10.2 | 644 | |
| First set | 70%–75% | 72.3% | 67.3% | -5.0 | 400 | |
| First set | 75%–80% | 77.3% | 71.9% | -5.3 | 260 | |
| First set | 80%–85% | 82.2% | 80.8% | -1.4 | 125 | |
| First set | 85%–90% | 87.2% | 81.3% | -6.0 | 80 | |
| First set / match | 35%–40% | 37.5% | 38.5% | +1.0 | 949 | |
| First set / match | 40%–45% | 42.5% | 42.2% | -0.3 | 907 | |
| First set / match | 45%–50% | 47.4% | 49.6% | +2.2 | 784 | |
| First set / match | 50%–55% | 52.3% | 49.1% | -3.2 | 633 | |
| First set / match | 55%–60% | 57.4% | 48.1% | -9.4 | 543 | |
| First set / match | 60%–65% | 62.3% | 50.7% | -11.6 | 408 | |
| First set / match | 65%–70% | 67.2% | 63.0% | -4.3 | 305 | |
| First set / match | 70%–75% | 72.3% | 64.3% | -8.0 | 213 | |
| First set / match | 75%–80% | 77.3% | 73.3% | -4.0 | 135 | |
| First set / match | 80%–85% | 82.2% | 74.0% | -8.2 | 77 | |
| First set / match | 85%–90% | 87.0% | 82.3% | -4.7 | 62 | |
| Games handicap | 35%–40% | 37.5% | 42.5% | +5.0 | 4107 | |
| Games handicap | 40%–45% | 42.5% | 46.5% | +4.0 | 3705 | |
| Games handicap | 45%–50% | 47.5% | 49.3% | +1.8 | 3581 | |
| Games handicap | 50%–55% | 52.5% | 50.7% | -1.8 | 3581 | |
| Games handicap | 55%–60% | 57.5% | 53.5% | -4.0 | 3705 | |
| Games handicap | 60%–65% | 62.5% | 57.5% | -5.0 | 4107 | |
| Games handicap | 65%–70% | 67.6% | 61.1% | -6.5 | 4463 | |
| Games handicap | 70%–75% | 72.5% | 65.1% | -7.4 | 4987 | |
| Games handicap | 75%–80% | 77.5% | 69.9% | -7.7 | 5933 | |
| Games handicap | 80%–85% | 82.6% | 74.5% | -8.1 | 7105 | |
| Games handicap | 85%–90% | 87.6% | 80.3% | -7.3 | 9016 | |
| Games handicap | 90%–95% | 92.7% | 87.4% | -5.2 | 12768 | |
| Games handicap | 95%–100% | 97.9% | 95.6% | -2.3 | 26307 | |
| Match winner | 35%–40% | 37.5% | 40.5% | +3.0 | 686 | |
| Match winner | 40%–45% | 42.6% | 42.3% | -0.3 | 800 | |
| Match winner | 45%–50% | 47.6% | 47.6% | +0.1 | 760 | |
| Match winner | 50%–55% | 52.4% | 52.4% | -0.1 | 760 | |
| Match winner | 55%–60% | 57.4% | 57.8% | +0.3 | 800 | |
| Match winner | 60%–65% | 62.5% | 59.5% | -3.0 | 686 | |
| Match winner | 65%–70% | 67.3% | 61.2% | -6.1 | 578 | |
| Match winner | 70%–75% | 72.4% | 59.9% | -12.5 | 524 | |
| Match winner | 75%–80% | 77.3% | 64.3% | -13.0 | 423 | |
| Match winner | 80%–85% | 82.3% | 75.4% | -6.9 | 333 | |
| Match winner | 85%–90% | 87.4% | 78.0% | -9.3 | 232 | |
| Match winner | 90%–95% | 92.2% | 88.8% | -3.4 | 134 | |
| Match winner | 95%–100% | 96.5% | 94.0% | -2.5 | 84 | |
| Odd/Even | 45%–50% | 49.8% | 50.5% | +0.7 | 4554 | |
| Odd/Even | 50%–55% | 50.2% | 49.5% | -0.7 | 4554 | |
| Set handicap | 35%–40% | 37.4% | 38.3% | +1.0 | 840 | |
| Set handicap | 40%–45% | 42.5% | 41.2% | -1.3 | 753 | |
| Set handicap | 45%–50% | 47.5% | 44.3% | -3.1 | 690 | |
| Set handicap | 50%–55% | 52.5% | 55.7% | +3.1 | 690 | |
| Set handicap | 55%–60% | 57.5% | 58.8% | +1.3 | 753 | |
| Set handicap | 60%–65% | 62.6% | 61.7% | -1.0 | 840 | |
| Set handicap | 65%–70% | 67.6% | 61.2% | -6.4 | 1030 | |
| Set handicap | 70%–75% | 72.5% | 68.0% | -4.5 | 1161 | |
| Set handicap | 75%–80% | 77.5% | 72.2% | -5.3 | 1282 | |
| Set handicap | 80%–85% | 82.5% | 74.7% | -7.7 | 1255 | |
| Set handicap | 85%–90% | 87.5% | 77.1% | -10.4 | 1024 | |
| Set handicap | 90%–95% | 92.3% | 85.7% | -6.6 | 733 | |
| Set handicap | 95%–100% | 99.9% | 98.3% | -1.6 | 9448 | |
| Set score | 35%–40% | 37.3% | 34.9% | -2.4 | 704 | |
| Set score | 40%–45% | 42.4% | 35.3% | -7.2 | 553 | |
| Set score | 45%–50% | 47.3% | 37.8% | -9.5 | 405 | |
| Set score | 50%–55% | 52.2% | 48.8% | -3.5 | 285 | |
| Set score | 55%–60% | 57.3% | 49.5% | -7.8 | 200 | |
| Set score | 60%–65% | 62.4% | 57.4% | -5.0 | 136 | |
| Set score | 65%–70% | 67.6% | 64.0% | -3.7 | 86 | |
| Straight sets | 35%–40% | 37.5% | 35.8% | -1.7 | 1028 | |
| Straight sets | 40%–45% | 42.7% | 39.8% | -2.9 | 1285 | |
| Straight sets | 45%–50% | 48.4% | 42.5% | -6.0 | 3552 | |
| Straight sets | 50%–55% | 51.5% | 56.2% | +4.7 | 3432 | |
| Straight sets | 55%–60% | 57.2% | 55.3% | -1.9 | 932 | |
| Straight sets | 60%–65% | 62.2% | 60.9% | -1.4 | 460 | |
| Straight sets | 65%–70% | 67.3% | 67.2% | -0.1 | 253 | |
| Straight sets | 70%–75% | 72.2% | 64.3% | -7.9 | 129 | |
| Straight sets | 75%–80% | 77.3% | 69.9% | -7.4 | 113 | |
| Total games | 35%–40% | 37.8% | 39.4% | +1.6 | 8608 | |
| Total games | 40%–45% | 42.9% | 42.5% | -0.4 | 8333 | |
| Total games | 45%–50% | 47.7% | 48.0% | +0.3 | 10679 | |
| Total games | 50%–55% | 52.3% | 52.0% | -0.3 | 10679 | |
| Total games | 55%–60% | 57.1% | 57.5% | +0.4 | 8333 | |
| Total games | 60%–65% | 62.2% | 60.6% | -1.6 | 8608 | |
| Total games | 65%–70% | 67.2% | 66.2% | -1.0 | 7525 | |
| Total games | 70%–75% | 72.6% | 73.7% | +1.0 | 5530 | |
| Total games | 75%–80% | 77.7% | 74.3% | -3.5 | 2474 | |
| Total games | 80%–85% | 82.2% | 79.0% | -3.2 | 5105 | |
| Total games | 85%–90% | 86.6% | 82.7% | -4.0 | 2621 | |
| Total games | 90%–95% | 92.2% | 88.8% | -3.4 | 7414 | |
| Total games | 95%–100% | 96.9% | 93.3% | -3.6 | 913 | |
| Total sets | 35%–40% | 37.8% | 34.9% | -2.9 | 324 | |
| Total sets | 40%–45% | 42.8% | 37.4% | -5.4 | 732 | |
| Total sets | 45%–50% | 48.6% | 39.0% | -9.6 | 3147 | |
| Total sets | 50%–55% | 51.4% | 56.9% | +5.5 | 3147 | |
| Total sets | 55%–60% | 57.2% | 56.8% | -0.3 | 732 | |
| Total sets | 60%–65% | 62.2% | 62.3% | +0.1 | 324 | |
| Total sets | 65%–70% | 67.2% | 68.9% | +1.7 | 167 | |
| Total sets | 70%–75% | 72.1% | 67.1% | -5.0 | 85 | |
| Total sets | 75%–80% | 77.5% | 66.7% | -10.9 | 63 |
How the model works
Each team carries an attack and a defence rating on
the log scale. The goals a home side is expected to score are
exp(attackhome + defenceaway + home advantage), and the away side's
are exp(attackaway + defencehome). Those two numbers feed a pair of
Poisson distributions, combined into a full scoreline matrix from which every market —
1X2, over/under, both teams to score, exact score — is read off.
Two departures from the textbook version matter:
- Time decay. Each historical match is weighted
exp(−xi · days ago), so recent form counts for more than a result from two seasons back. - An xG target. Fitting on expected goals rather than goals removes finishing variance, which is mostly noise. In the backtest this improved accuracy without hurting log loss.
The rho parameter is Dixon and Coles' correction to the
low-scoring cells (0-0, 1-0, 0-1, 1-1), where treating the two scores as independent is known to misfit.