workabout
writing
< back to work

matchday / 2026

2026 · Machine learning · Product

Matchday

Football predictions built without using bookmaker odds.

Overview

Matchday turns ten seasons of match data into honest P(H/D/A) calls — no odds inputs, bookmaker as benchmark, and a live app with fixtures, manual predictor, title simulator, and disclosed metrics.

Role
ML engineering · product
Year
2026
Stack
XGBoost · FastAPI · Next.js · Python · TypeScript · Elo + form features
Live
Visit ↗
Source
GitHub ↗
matchday.pxxl.click
Matchday product preview

01

An honest comparison to the bookmaker

Most football models either leak odds into the features or hide behind accuracy. I wanted a model that could survive an honest comparison to the bookmaker — trained only on what is known before kickoff, evaluated on log-loss, and clear about where it still loses.

02

Designing the pre-match feature pipeline

A 23-feature fair-play pipeline: Elo plus margin Elo, 5/10-match rolling form, head-to-head, rest days, and goals/shots/corners averages — with leakage checks and pinned train/val/test windows so no future information ever contaminates a pre-match prediction.

03

Why XGBoost, and what it beat

matchday.pxxl.click
Matchday season record dashboard showing 50.7 percent accuracy over 146 calls
Published season record — log-loss disclosed, not hidden

A tuned XGBoost multiclass model beat both a logistic-regression baseline and the training-prior naive. The choice was empirical rather than fashionable: gradient boosting captured the non-linear interactions between form, strength, and rest that linear models flattened — verified on a locked 2024/25 test of 1,752 matches, not on validation peeking.

04

Evaluating against bookmaker probabilities

Locked 2024/25 test: naive 1.077 vs XGB 0.985 vs B365 bookmaker 0.965. Live 2026/27-partial test (146 matches): 0.989 log-loss at 50.7% accuracy. The model still loses to the bookmaker — published, not hidden. Taking no odds as input is a deliberate handicap: it keeps the comparison honest but concedes the single strongest pre-match signal that exists.

05

Serving predictions with FastAPI and Next.js

Shipped behind a FastAPI backend (predict, fixtures, evaluate, simulation) with a Next.js frontend: weekly fixtures, name-your-tie predictor, a 2,000-season Monte Carlo title simulator, Dixon-Coles scorelines stamped conditional on XGB, and a model page that publishes log-loss instead of hiding it. Train/serve parity is enforced by a point-in-time test, 51 pytest gates guard regressions, and the full loop — refresh, retrain, reload, simulate — runs from a Makefile in production.

matchday.pxxl.click
Matchday weekly fixtures board showing Premier League ties with Call It buttons
Weekly fixtures — every tie gets a call
matchday.pxxl.click
Matchday manual predictor for Manchester United vs Manchester City with home, draw and away probabilities
Name-your-tie predictor with honest probabilities
matchday.pxxl.click
Matchday title simulator table after 2,000 simulated seasons
2,000-season Monte Carlo title simulator

Structure

  1. 01

    Ten seasons of matches

  2. 02

    23 pre-match features

  3. 03

    XGBoost

  4. 04

    FastAPI

  5. 05

    Next.js product

The result

Locked 2024/25 test (1,752 matches): naive 1.077 → XGB 0.985 vs B365 bookmaker 0.965. Live 2026/27-partial test (146 matches): 0.989 log-loss at 50.7% accuracy. Train/serve parity is enforced by a point-in-time test, 51 pytest gates guard regressions, and the full loop — refresh, retrain, reload, simulate — runs from a Makefile in production on Pxxl + Vercel.

0.985 log-loss
1,752-match locked test
5 leagues live

If I built it again

The honest benchmark changed the project from a model into a product: losing to the bookmaker publicly is what makes the rest of the numbers believable. Next iteration is calibration by league — the residual errors are not evenly distributed, and the model knows it.

Further reading + source

GitHub ↗Live product ↗

Next project

Firstpass→

2026 · Experiments