Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

xPoints

Explainable, self-calibrating football match-prediction engine — built for the 2026 World Cup.

tests python license

xPoints predicts World Cup match results by maximising expected points under the Kicktipp 3/1/0 scoring scheme. It anchors to de-vigged market odds, applies a calibrated tournament draw-nudge, and predicts the argmax tendency plus its modal scoreline. Every probability is computed by tested code — not by hand — and the engine grades its own predictions after each match and re-calibrates.

The methodology is the spec: methodology.md is a human-readable decision spec, and engine/predict.py deterministically executes it. Change a rule in prose → change one constant in code → the backtest confirms whether it helped.

Why it's more than a toy

  • Expected-value decision rule. Under 3/1/0, EV = 1·P(tendency) + 2·P(exact score). The engine predicts the argmax-EV tendency, then the single most-likely scoreline within it — it never hedges a draw it can't justify.
  • Self-calibrating, with a guardrail against overfitting. After each batch it computes Brier score and by-tier hit-rate (engine/season.py) and proposes a re-weight only after ≥8 probability-bearing games — the discipline that caught an early over-tune (documented in the calibration log).
  • Honest confidence tiers. Every pick ships as 🟢 clear-favourite / 🟡 lean / 🔴 coin-flip, with a stated ceiling (~58–65% overall, ~80% on the 🟢 slate). No inflated accuracy claims.
  • Human-in-the-loop by design. The engine runs data → compute → cards → grade → propose automatically; the human owns exactly three judgment calls (RUNBOOK-HITL.md). Designing that automation/judgment boundary is the point.
  • A written track record. methodology.md §5 is a calibration log across four engine versions — including post-mortems of calls that were wrong. The engine beats hand-managed picks (62% vs 46% tendency) precisely because it removes emotional hedging.

How a prediction is made

market odds (free sources)
   │  de-vig   strip the overround → true P(home / draw / away)
   ▼
+6% tournament draw-nudge     market underprices draws (~11 pts, full-sample stable)
   │
+5–7% draw overlay            only if Sports Mole / Forebet call a draw; can only reinforce
   ▼
argmax(P_home, P_draw, P_away)  →  tendency  →  confidence tier  (🟢 / 🟡 / 🔴)
   │
modal scoreline within tendency, anchored to the O/U line   →   final pick + card
   │
after kickoff:  grade (3/1/0)  →  Brier + by-tier attribution  →  propose re-weight (≥8 games)

Results (live, in-flight)

Honest, no cherry-picking — the same rule applied to every game:

  • ~73% tendency on the 🟢 clear-favourite slate — the "confident product".
  • ~62% engine tendency across a full batch, vs 46% on earlier hand-managed picks: discipline beats gut.
  • Overall was dragged down by an abnormal early draw cluster (group stage ran ~34% draws vs market-implied ~20%); as draws regress, overall climbs toward ~60%.

Match-by-match log in results-log.md; every calibration decision in methodology.md.

Quickstart

pip install -r requirements.txt
python -m pytest              # 62 tests, ~1s

Predict a matchday from a fixture:

python -m engine.run_matchday matches/2026-06-28_Panama-vs-England.json

Live odds are optional — set ODDS_API_KEY (see .env.example) to pull from The Odds API; without it you pass odds/probabilities directly in the fixture.

Architecture

engine/
  predict.py      decision rule: de-vig → nudge → argmax → tier → scoreline
  scoring.py      3/1/0 grading
  backtest.py     replay predictions against actual results
  season.py       Brier score + by-tier accuracy + draw-rate calibration
  weights.py      propose_reweight() — guarded re-calibration (≥8 games)
  ko_strategy.py  knockout mode (extra time / penalties, no draws)
  connectors/     odds_api.py — The Odds API, env-based key
tests/            62 tests covering every engine module
matches/ teams/   per-match & per-team data (json + human-readable card)
methodology.md    the decision spec the engine executes

Built with an AI-native workflow

Spec-driven and agent-orchestrated (Claude Code): the methodology is authored as an executable spec, the engine ports it deterministically, and 62 tests lock the behaviour. The human owns the judgment — the strategy, the calibration calls, and every pick submitted. That spec-first, test-locked, human-in-the-loop loop is how I take a system from 0→1.

Tech

Python 3.12 · pydantic · pytest. Dependency-light and fully deterministic — every number is reproducible and tested.

Scope: built for the Kicktipp 3/1/0 prediction game. Public betting odds are used only as the best-calibrated probability prior, not for wagering.

License

MIT — see LICENSE.

About

Explainable, self-calibrating football match-prediction engine (World Cup 2026): EV-optimal picks from de-vigged odds, self-grading backtests, 62 tests.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages