TFF Fantasy League Optimiser

Tagline: Optimal TFF Fantezi Lig squads from form, fixtures, and integer programming — not vibes.

Built with: Python · PuLP · Pandas · Sofascore · FotMob · TFF Fantezi Lig API · Pillow


Inspiration

Fantasy football in Turkey’s Süper Lig is intense: 100M budget, strict squad rules, weekly fixtures, and scoring that rewards minutes, clean sheets, goals/assists, and bonuses. Most tools stop at price lists or gut picks. We wanted something that actually answers: given this week’s opponents and real form, what’s the best legal 15-man squad? Especially early in the season — when one good match can look like a season — we needed Bayesian-style caution, not hype.

What it does

TFF Fantasy League Optimiser builds a weekly recommended squad for the official TFF Fantezi Lig:

  • Pulls player prices and availability from TFF
  • Estimates expected points from Sofascore + FotMob (form, season stats, xG/xA, minutes)
  • Respects official scoring (60+ minutes, CS, cards, bonuses, etc.)
  • Solves an integer program for the best formation, starting XI, bench, and captain under 100M / 2-5-5-3 / max 3 per club
  • Advises whether to play a manager card or save it
  • Exports a clean weekly PNG report (pitch, fixtures, card call)

One command (calistir.bat or python -m src.main) → ready-to-use lineup.

How we built it

Python end-to-end pipeline:

  1. Ingest — TFF client for prices/availability; Sofascore & FotMob for performance (cached)
  2. Score — Per-player expected points with opponent strength, home/away, early-season blending of prior season when sample size is tiny
  3. Calibrate — External-league → Süper Lig translation from historical transfers (league_translation.json), not a flat “foreign = weaker” guess
  4. Optimize — PuLP integer program over formations; weighted bench for auto-subs
  5. Advise — Manager-card opportunity ranking vs. saving the card
  6. Report — Pillow-generated weekly pitch graphic

Challenges we ran into

  • Early-season noise: One clean sheet can look like 100% CS probability; unplayed clubs look like 0%. We had to shrink small samples and blend with last season.
  • Same-club goalkeepers: Without start probability, a backup with one lucky CS could beat the real #1.
  • New transfers / foreign leagues: Mapping Ligue 1 or Championship rates into Super Lig TFF points needed real transfer history, not hand-waved multipliers.
  • Name matching & availability: TFF vs Sofascore vs FotMob naming, plus injured/suspended exclusions.
  • Card advice without inventory: We rank opportunity value (use vs save), not account stock.

Accomplishments that we're proud of

  • A full legal fantasy squad in one run — not just a ranked list
  • Transparent reasons per player (why this XP, start %, CS blend)
  • Robust early-season / GK / form fallback logic that doesn’t overfit week 1
  • League translation calibrated on real Super Lig arrivals
  • A weekly PNG report you can actually share or screenshot into decisions

What we learned

Expected points ≠ last match points. Sample size, role (starter vs backup), fixture difficulty, and prior-season priors matter more than a viral one-off performance. Also: fantasy scoring is a product of team defense and individual minutes — modeling only goals misses half the game for GKs and defenders.

What's next for TFF Fantasy League Optimiser

  • Live / confirmed XI signals when available
  • Multi-week transfer planning (bank, hits, chip windows)
  • Stronger integration of official TFF points for mid-season calibration
  • Optional web UI on top of the same optimizer
  • More automated regression checks on “week 1 traps” (hot GKs, zero-sample clubs)

Built With

  • cursor
  • fantasyleague
  • football
  • fotmob
  • pandas
  • sofascore
  • tff
  • ts
Share this project:

Updates

Submission history