wraith-tdf-predictor 🚴💨
Who cracks the top 10 in July? Six seasons of ProCyclingStats results, a from-scratch model, and a Tissot fantasy team picked by exact knapsack — all in pure Python. No torch, no sklearn, no 200 MB wheel for a model with nine weights.
The 2026 hot take so far: Pogačar. Groundbreaking stuff.
What it does
- Scrapes grand tours, one-week stage races, monuments and top classics (men's elite, 2021–2026) into SQLite
- Clusters riders into archetypes with hand-rolled k-means
- Predicts top-10 finishes with class-weighted logistic regression (test AUC ~0.89 — form really is everything in cycling)
- Picks a 10-rider, 120-star Tissot fantasy team via 0/1 knapsack with cardinality, backtested leave-one-year-out against the hindsight-optimal team
- Publishes a static predictions page (
data.json) with per-stage teams, jersey picks, and pred-vs-actual grading during the Tour
Install
pip install wraith-tdf-predictor # or: uv add wraith-tdf-predictor
Runtime dependencies: procyclingstats and cloudscraper. That's it.
Python 3.12+.
Run it
From a clone:
git clone https://git.thomaspeoples.com/thomaspeoples/wraith-tdf-predictor.git
cd wraith-tdf-predictor
uv run poe setup # deps, hooks, .env from template — once
uv run poe ingest # scrape PCS -> data/raw/*.json (polite, cached)
uv run poe db # load -> data/races.db (SQLite)
uv run poe model # archetypes + top-10 model
uv run poe fantasy # backtest + 2026 team pick
uv run poe publish # data.json for the static predictions page
docker compose up -d # browse the DB at :8080
uv run poe update # daily during the Tour: ingest new stage if
# raced, retrain, republish -- no-op otherwise
Outputs land in data/: archetypes.json, model.json, and a
printed team that will absolutely not win your league.
Configuration
Everything configurable lives in .env (copied from
.env.example by poe setup, never committed):
| Variable | Default | Purpose |
|---|---|---|
DATA_DIR |
./data |
Scraped data, SQLite DB, model outputs |
WWW_DIR |
$DATA_DIR/www |
Where poe publish writes data.json |
TISSOT_USER / TISSOT_PASS |
— | Only for scraping the Tissot game yourself |
Poe tasks load .env automatically; direct python -m runs want
uv run --env-file .env ....
Where the data comes from (and how politely it's scraped): docs/SOURCES.md.
Hacking on it
uv run poe test # pytest, coverage >80% enforced
uv run poe tidy # ruff lint + format
uv run poe docs-serve # MkDocs on :8000
uv run cz commit # commits go through commitizen, no exceptions
Full workflow in CONTRIBUTING.md.
License
MIT — see LICENSE.
Metadata
Release files for wraith-tdf-predictor 0.12.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| wraith_tdf_predictor-0.12.0.tar.gz | 162.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| wraith_tdf_predictor-0.12.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 194.9 kB
Release files / wraith_tdf_predictor-0.12.0.tar.gz
| Download URL | wraith_tdf_predictor-0.12.0.tar.gz |
|---|---|
| Size | 162.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c095607c50bae549675e095618e4ec8d4b7fbbb1146199f68aa1c0d5f300d30f
|
|
BLAKE2b-256 checksum How to use checksums |
4f06efdb6883777cd3501b8cbb845ac9a8693ed86b98b55d5816dcc3d5775d9e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / wraith_tdf_predictor-0.12.0-py3-none-any.whl
| Download URL | wraith_tdf_predictor-0.12.0-py3-none-any.whl |
|---|---|
| Size | 32.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
683d5acea13f07ce5257d650ab7c6a85bcbdde10cd58ca1b1ac79e2507791def
|
|
BLAKE2b-256 checksum How to use checksums |
e29b85bbab7187838b3cb1ec63a33c8f0b610199e81121af3e4deaf528f3d432
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|