Skip to main content

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)

Source distribution for wraith-tdf-predictor 0.12.0
File Size Uploaded
wraith_tdf_predictor-0.12.0.tar.gz 162.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for wraith-tdf-predictor 0.12.0
File Interpreter ABI Platform
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}

Release history Release notifications | RSS feed

This release

0.12.0 This release

2 release files

0.11.0

2 release files

0.9.0

2 release files

0.8.0

2 release files

0.7.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page