1. Data
matches with usable prices across the Premier League, Championship, Bundesliga, La Liga, Serie A and Ligue 1, from football-data.co.uk. 2018/19 only warms up the ratings. The last match is .
- Bet price: pre-closing quote, cut by 1% for slippage at Bet365 or 2% on the best market quote.
- Benchmark: market-average closing odds with the margin removed. Pinnacle isn't used because its columns stop during 2025/26.
- Exchange: Betfair prices exist from 2024/25 and are net of an assumed 2% commission.
2. Fair probability
Remove the margin
Rate the teams
Each team has attack and defence ratings, refitted per fixture date using only earlier matches.
λ(away) = μ · attack(away) · defence(home)
Older matches fade with a half-life of days. The input mixes goals and shots on target . Scorelines use a Poisson grid with the Dixon-Coles low-score correction (ρ = −0.08).
Blend with the market
A second-stage softmax fitted on 2019/20–2022/23:
Fitted weights for the 1X2 market: a = , b = .
3. Edge and staking
stake = bankroll · min( cap, K · EV / (O − 1) )
Sample settings: EV at least , odds between , K = 0.25, cap = 2%, one bet per match and market.
4. Test protocol
| Step | Seasons | What happens |
|---|---|---|
| Warm-up | 2018/19 | Ratings only |
| Calibrate | 2019/20–2022/23 | Rating settings and blend fitted |
| Tune | 2023/24–2024/25 | rule sets ranked by lower CLV bound |
| Holdout | 2025/26 | Frozen rules, opened once |
| Forward replay | 2026/27 to date | Frozen rules, opened once |
Two changes came before the holdout was opened: the minimum tuning sample fell from 300 to 100 bets, because no Bet365 rule set reached 300, and the best-price route was added. Both are disclosed because they widen the search.
5. Assumptions and limits
- Pre-closing quotes are snapshots. Their exact timestamp and available stake aren't in the data.
- Best-price quotes may be stale, which is the suspected reason this sample failed. The data can't prove it.
- 2020/21 includes matches without crowds.
- Account limits at retail books aren't modelled.
- The six gates were set after this run, so they're a proposal for your project, not proof about this one.
6. Result
7. Quick start (planned shape)
The research pipeline below runs today on Node 20 or later. The live bot would be delivered and documented at this level, and the language can be Python if you prefer.
node --version # Node 20+ node pipeline/01_model.js # fit ratings and blend, walk-forward node pipeline/02_backtest.js # tune, freeze, test, export report
Live setup would need your exchange API key and app key in environment variables, with paper mode on by default. Monitoring covers daily P/L, drawdown, CLV and an emergency stop.