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.
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. The live data couldn't be loaded, so the table below may be empty.
| Gameweek | Points | Average | Total | Overall rank | Transfers (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.
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).
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
- Understat per-match expected goals and head-to-head match odds added nothing once the leak was gone, and neither is reliably available at a deadline, so both are out of the model.
- Dropping the expected-points field entirely cost 0.004 in rank correlation on 2024/25, so the previous gameweek's value stays in.
- Priors from last season (prior-season points features, cross-season form, shrinkage towards last season) didn't help the early gameweeks.
- Dedicated captain models, an upside model and bookmaker scorer odds, didn't beat captaining the top prediction.
- Weighting recent rows more heavily didn't help.
- A six-gameweek horizon lost to three, and so did a two-point margin on hits in the single-gameweek optimiser.
Known gaps
- There's no chip scheduler. The replays can't separate chip schedules from noise, so the chip plan is mine.
- Predictions for the later gameweeks of a plan are weaker than for the next one, and there's no bonus-point model.
- The live entry is one season of one team. The tracker is a diary, and it doesn't validate anything.