Alexandre Dalban

Work · live season · 5 min read

Fantasy Premier League, predict and optimise

I built a point predictor and a squad optimiser, and they plan a real Fantasy Premier League entry each week of the 2026/27 season. The tracker below refreshes itself from the game's public API, so this page is also the entry's scoreboard.

Dates
March 2026 (engine, first models). Live-season rebuild August 2026. Leak fix and model rebuild September 2026. Running weekly.
Status
live season my own entry, updated after each gameweek
Role
Mine: engine, data collectors, predictor, optimiser, live-season tooling, backtests. Two contributors in April: a SHAP explainability script and an analysis report on the expected-points feature. Built with Claude Code.
Code
github.com/ADnocap/FPL-Optimizer, public

Season tracker

Each week the models propose the transfers, lineup, captain and bench order. I review the plan, and the reviewed plan is what goes onto the entry. Any gameweek where the entry departs from the optimiser's recommendation gets a note under the tracker.

Entry , season . Refreshed by a scheduled job that reads the public FPL API. I don't edit it by hand.

total points after gameweeks
overall rank among managers
gameweeks I scored above the average manager
cumulative points versus the average manager
Points per gameweek for the entry, against the average of all managers. The first few gameweeks aren't evidence of anything. A full season will be, and the chart is here to collect one by the end of May. Source: fantasy.premierleague.com public API, entry history and gameweek averages.
Overall rank after each gameweek. Lower is better. Source: as above.
GameweekPointsAverageTotalOverall rankTransfers (hit)Chip

Where the entry has departed from the optimiser's plan so far: in GW2 I didn't make the recommended transfer (João Pedro out, Gyökeres in), but I did make the captain switch. In GW3, GW4 and GW5 I picked a different captain from the model's (Haaland, João Pedro and Haaland instead of Bruno Fernandes, Bruno Fernandes and Stach). In GW5 I also declined the hits it wanted and rolled the free transfer. I missed the GW7 deadline, so the entry made no transfers that week and the planned triple captain wasn't played. I'll add later departures here.

How it works

The system is predict-and-optimise. A LightGBM point predictor estimates each player's expected points for the coming gameweeks from 121 features, trained on ten seasons of history plus the current season's completed gameweeks. The features come from the community's season archives and the game's own API (including its expected-points field from the previous gameweek), prior-season stats from Understat and FotMob, and bookmakers' player-prop odds.

The predictor has two parts. A minutes model gives the probability that a player doesn't play, plays under an hour, or plays an hour or more. Half of the prediction is those probabilities times the expected points in each case, and the other half is a points model that also sees them. The minutes model was the largest single gain, +0.015 in rank correlation, and it was better in all 38 gameweeks of both holdout seasons.

A mixed-integer programme (PuLP with the CBC solver) then plans transfers three gameweeks ahead under the real bank, selling-price and free-transfer rules, and only takes a four-point hit when the plan gains clearly more than four. It also picks the starting eleven, the captain, and a bench order weighted by auto-substitution probabilities. Flagged players are scaled by how often players with that flag have actually played.

Predictor accuracy

The main metric is the per-gameweek Spearman rank correlation between predicted and actual points, because the optimiser only needs the order to be right. Trained only on earlier seasons, the model scores 0.732 on 2024/25 and 0.742 on 2025/26. Over the first five live gameweeks of 2026/27 it scores 0.711, where the game's own expected points score 0.631. Five gameweeks is a small sample. It still under-predicts big hauls.

Per-gameweek Spearman correlation over 2026/27 gameweeks 1 to 5, every model trained only on complete earlier seasons. "Previous model" is the one I used for those gameweeks, which relied on the leaking feature described below. Source: training log of the model of record in the repository.

Earlier versions of this page reported higher numbers: 2,918 points on a 2024/25 replay and correlations around 0.78. They came from a feature that leaked. The season archives record the game's expected-points value after the gameweek, when it has already been recomputed with that gameweek's own points, and the model had learned to lean on it. Live, it only gets the value from before the deadline, which is why the first five gameweeks went worse than the backtests promised. The model now uses the previous gameweek's value, which is exactly what's known at a deadline.

Backtests

I replay whole seasons without chips. For each season the evaluation model is trained only on the seasons before it, and every gameweek goes through the rules engine (auto-substitutions, captain failover, free-transfer banking, hits).

Net season points in chip-free replays, the single-gameweek optimiser against the three-gameweek planner that now runs each week. Source: season replay script in the repository.

The planner beat the single-gameweek optimiser in every season, by 60 to 149 points. Differences under about 100 points are within the noise of one replay. The chip schedules I tested moved the totals by −145 to +84, about zero on average, so chip timing stays my decision, with the repository's chip evaluator giving the numbers at each decision point.

Experiments that didn't make it

Known gaps