A time-weighted Dixon-Coles bivariate Poisson model estimates each team's attack and defence strength from goals, and a second copy of the same model is fit on expected goals rather than goals. A gradient-boosted classifier adds form, rest and congestion effects. The three are blended with weights chosen on out-of-sample folds and the result is temperature-calibrated.
Every market on a match card — result, totals, both teams to score, clean sheets, correct score, and every combination — is a sum over the same joint scoreline distribution. That is why the numbers agree with each other: Over 2.5 and Under 2.5 sum to exactly 1, and a double chance equals the sum of its parts. Sites that model each market separately routinely publish boards that quietly contradict themselves.
Over/under and both-teams-to-score are listed apart from the match winner because they are a different question. They do not care who wins — they are driven by the total-goals distribution rather than by the difference between the two sides — and a goal model is being asked the thing it was actually built to answer, rather than having its output collapsed onto a three-way result.
They are also calibrated separately. The 1X2 row is temperature-scaled on out-of-fold predictions; the goal markets were not, and read straight off the scoreline matrix they are overconfident at both tails — confident predictions too confident in either direction, while the average looks unbiased. That is the worst possible shape of error for a table sorted by expected value, since sorting by EV is precisely a search for the tails. One temperature per market group, fit out of fold, shrinks them back toward the base rate. Complements are recomputed rather than scaled independently, so Over 2.5 and Under 2.5 still sum to exactly one.
Calibration cannot manufacture skill. Where a market turns out to be no better than its own base rate, shrinking simply makes the model say so — and the figure quoted above each table is that comparison, measured out of fold during training.
One inconsistency worth naming: same-match combinations are still computed from the raw joint distribution, so a combination involving a totals leg can disagree very slightly with the calibrated number on the card. They are shown to illustrate correlation rather than as priced selections, and recalibrating a joint distribution while preserving all its margins is a materially harder problem than scaling one number.
Each pair is de-vigged on its own rather than inheriting the match-winner overround. Books charge more margin on goals markets than on the 1X2 line, so borrowing the 1X2 margin would flatter every totals row. Only the side the model prefers is listed: the two sides of a two-way line are near mirror images, so showing both would double the table without adding information.
Two selections in the same match are correlated. A home win and over 2.5 goals tend to occur together, because the home team scoring is what drives both. Multiplying the two probabilities understates the true chance — often by 15–60%. Because the joint distribution is available, no independence assumption is needed: the combination is simply the sum of the cells satisfying both conditions.
Selections in different matches genuinely are independent, so those probabilities do multiply. So does the margin, which is the problem with accumulators and the reason each one is shown with its compounding cost.
Walk-forward only: train on the past, predict the next block, step forward. Prices are closing odds where available, because beating the closing line is the only benchmark that means anything. The model's log loss is reported against that line on every backtest, and the engine refuses to endorse a profitable-looking run that fails the test.
| Model | Value |
|---|---|
| trained_at | 2026-08-09T06:07:19.772682+00:00 |
| n_matches | 45215 |
| n_teams | 911 |
| date_from | 2019-02-22 |
| date_to | 2026-06-13 |
| val_log_loss | 0.9963 |
| val_log_loss_market | 0.9543 |
| blend | {'dixon_coles': 0.396, 'dixon_coles_xg': 0.016, 'gbm': 0.587} |
| temperature | 0.958 |
| extras | ['xg', 'congestion', 'h2h', 'injuries'] |
It is not a tipping service and not financial advice. In honest backtesting this model does not consistently beat closing prices — which is the normal result, because liquid football markets absorb most of the available signal. Published selections should be expected to lose money over time. The site exists to show the model's reasoning and track its calibration in public, which is a much better reason to publish than pretending to have found free money.