How it works
Win % (1X2) — no odds used
Every match gets the SportsOracle model: an Elo rating that accounts for opponent quality plus time-decayed attack/defence ratings (Dixon-Coles, with a low-score draw correction), built only from results before kick-off. Where both head coaches and their records are known, it is mixed 70% SportsOracle + 30% coach model and then calibrated (adjusted on earlier matches so that our 70% wins about 70% of the time). Each card says which was used.
Over/Under 2.5 & BTTS — no odds used
From the SportsOracle model's scoreline probabilities (expected goals for each side), calibrated the same walk-forward way. The coach model predicts only the winner, so goals markets use the SportsOracle model alone.
Coach model
Point-in-time coach records from our stored results (points per game, goal difference, win rate, coach-v-coach meetings, style matchup), using Transfermarkt appointment dates; current head coaches only. Style tags are today's labels (mild hindsight).
Value badges
A green +% badge = our % is at least 2% above Pinnacle's no-margin %, at Pinnacle no-margin odds 1.12–3.00. Every badge is logged on Value bets and settled automatically.
Analysis picks
Matches with both a coach H2H record and squad values: squad value ratio + managers' H2H + home advantage, no odds. Backtest ties the SportsOracle model and uses today's squad values (hindsight-biased). Details on Analysis.
Calibration
"When we say 70%, did it happen ~70% of the time?" Reliability tables and scores are on Calibration and Performance.
Data sources
Results and odds history: football-data.co.uk. Fixtures and kick-off times: Sportmicro, Transfermarkt and The Odds API. Prices: Pinnacle and the market average. Squad values, injuries and coach dates: Transfermarkt.
Research history (how the football model was built, v2)
Real data from football-data.co.uk (11 leagues, Aug 2024 – today, about 8,400 results with Pinnacle and market-average prices). Every change was tested on a time split: ratings are built match by match with no lookahead, settings are chosen on the fit period (Oct 2024 – Dec 2025, 4,929 matches) and checked once on the hold-out (Jan 2026 – today, 2,779 matches).
1 · Opponent-adjusted ratings
League-wide Elo. Every team has one rating, updated after every league match against the actual opponent: K = 25, home advantage 100 Elo points, multiplied by ln(1 + goal difference) + 1 for wins by more than one goal. At a new season ratings keep 80% and regress 20% to the league mean; promoted / new teams start 80 points below the league mean. The Elo gap moves expected goals: λ × exp(±1.3·gap/800) around the league average and home advantage.
Attack/defence (Dixon-Coles style). Before every match day each league is refitted as a Poisson model with one attack and one defence number per team, a home effect and a league scoring level, weighting older matches down with a 480-day half-life over the last 2 years, and shrinking teams with little data toward average (prior 10 matches; teams new to the league start below average).
Final expected goals = geometric mean of the two (50/50 in log space) — better than either alone on all three markets.
| Hold-out log-loss | 1X2 | O/U 2.5 | BTTS |
|---|---|---|---|
| Old model (last-10 form + form Elo) | 1.0280 | 0.6872 | 0.6922 |
| League-wide Elo | 1.0098 | 0.6781 | 0.6833 |
| Attack/defence (time-decayed) | 1.0045 | 0.6815 | 0.6850 |
| Elo + attack/defence (kept) | 1.0038 | 0.6760 | 0.6819 |
| Market alone (no margin) | 0.9841 | 0.6768 | — |
2 · Draws: Dixon-Coles low-score correction
Independent Poisson put the draw at 23.6% on the fit period vs 25.5% actual. A Dixon-Coles correction with ρ = -0.09 lifts 0-0 and 1-1 (and trims 1-0 / 0-1): predicted draw rate 25.6%. Hold-out 1X2 log-loss 1.0038 → 1.0026, BTTS 0.6819 → 0.6809, O/U unchanged. Kept.
3 · Calibration and the market blend
Platt scaling (and isotonic for O/U, BTTS) fitted on the fit period made the hold-out worse (1X2 1.0026 → 1.0043, O/U 0.6760 → 0.6778, BTTS 0.6809 → 0.6824), so the raw model is used. Dropped.
History: fitting a model-vs-market blend on the fit period gave market alone as the best single forecast; the site used to show 0.9 × market + 0.1 × model. Replaced on 30 Oct 2026 by the market-free method below.
4 · Fatigue and schedule
Tested rest-day difference, a ≤3-day turnaround flag and matches in the last 14 days as adjustments to expected goals. The fitted effects were small, statistically indistinguishable from zero and partly the wrong sign; hold-out was flat or worse (1X2 1.0026 → 1.0027, BTTS 0.6809 → 0.6810). The source files only contain league games, so cup and European midweek matches can't be seen; getting them would need extra API calls. Dropped.
5 · Value rule
Same rule as tennis: edge = final % ÷ Pinnacle's no-margin % − 1 ≥ 2%, at Pinnacle no-margin odds 1.12–3.00, only when a Pinnacle price exists (1X2 always in the upcoming file; Pinnacle O/U is missing since 2026). With the 0.9 blend this means our model rates the side ≥20% above Pinnacle. The threshold was the best of a grid on the fit period; the hold-out is shown as it came out:
| Pre-match, flat 1 unit | Bets | Win % | ROI @ Pin no-margin | ROI @ best price |
|---|---|---|---|---|
| 2024 (fit) | 128 | — | +1.2% | −1.2% |
| 2025 (fit) | 254 | — | +7.6% | +4.6% |
| Fit total | 382 | 42.4% | +5.4% | +2.6% |
| 2026 hold-out | 49 | 38.8% | −2.1% | −3.8% |
The Filters page recomputes the same rule from stored data (2024: 128 bets, −0.6%; 2025: 253 bets, +5.9%; 2026: 48 bets, −5.0% at the Pinnacle no-margin price). One bet either side of the 2% line moves a 49-bet return by about 4 points. The hold-out is small (Pinnacle prices are missing from mid-January to May 2026) and negative. Treat a flag as "the model disagrees with Pinnacle", not as proven profit. A price you type on an acca leg uses your own stake rules in the same odds range.
Kelly suggestion = (p·odds − 1)/(odds − 1) × your fraction (default ¼ Kelly), capped at 2% of bankroll by default. Treat it as an upper bound, not advice.
6 · Prices
Each pick shows the final probability and the Pinnacle price where available, otherwise the market average (Avg). Both-teams-to-score has no published price, so it shows model fair odds. Upcoming odds are refreshed about twice a week, so prices can be days old. Bookmakers such as SportyBet and 22bet have no public feed — type their price on an acca leg.
7 · Backtests and past dates
Filters walk ~8,000 results in date order. Form rules use the 10 games before each match; model percentages come from ratings built only on earlier days. Form filters settle at closing market-average odds; the value rule settles at Pinnacle's pre-match price (no-margin and actual) and is reported by year. Picking a past date on Today shows the same pre-match percentages.
Known weaknesses
- No injuries, line-ups, motivation or cup/European schedule.
- xG is not used by the ratings (only goals; the source files have no xG).
- The market is sharper than the model; a model edge is usually model error.
Match card model box
- Model only, no bookmaker prices (prices appear on the market buttons below the box).
- Corners: expected corners = league average × each club's last-10 for/against; H2H = average corners per club in stored past meetings, either venue (count in brackets).
- Goals: goals scored–allowed per league game this season, all venues; * = fewer than 5 games this season, so last season is included.
- H2H goals: goals scored–allowed per club in all stored past meetings before the match, either venue (count in brackets).
- Tennis and hockey boxes: model % only; tennis sets and +5 games and all hockey % are calibrated on a walk-forward hold-out (see each sport's Calibration page); hockey buttons show Pinnacle prices when stored.
Other sports
Each sport has its own method page: Tennis · Hockey · Basketball.