Skip to content

Repository files navigation

ff-model

NFL fantasy football projections: a small quantile transformer (trained on a free SageMaker Studio Lab T4) versus classical baselines, evaluated honestly with walk-forward backtests, published as a static site that updates itself weekly during the season.

Design spec: docs/superpowers/specs/2026-07-09-fantasy-football-model-design.md

Quickstart

python -m venv .venv                # Python >= 3.10
source .venv/Scripts/activate       # POSIX: source .venv/bin/activate
.venv/Scripts/python.exe -m pip install -e ".[dev]"   # POSIX: .venv/bin/python
pytest                          # unit tests (offline)
pytest -m integration           # network tests against live nflverse data

python -m ffmodel.data.pull     # cache 2012-2025 data to data/raw/
python -m ffmodel.eval.run      # walk-forward backtest -> models/backtests/baselines.json

Training on SageMaker Studio Lab

  1. Start a GPU runtime (T4; 4h/day quota) and open a terminal.
  2. Once: git clone <repo-url> && cd <repo> && pip install -e ., then set your git identity (git config --global user.name "..." and user.email "...") and authenticate for pushing — a fresh Studio Lab runtime has neither configured. Use a GitHub personal access token as the clone/push credential, or run gh auth login if the gh CLI is available.
  3. Open notebooks/train_studio_lab.ipynb and run the cells top to bottom. Each config trains one walk-forward artifact (models/transformer/v1/through<year>/); training checkpoints every epoch, so if the session dies, restart the runtime and rerun the same cell adding --resume.
  4. The last cell runs the full bake-off and commits artifacts + results. Note on fairness: the transformer reserves the season right before each test year as an early-stopping validation set, while the baselines are fit through that season with no holdout — a small handicap for the transformer that we call out honestly in the results rather than hide.

Local CPU training works identically (slower): same commands, no notebook needed.

Automation (GitHub Actions)

Three workflows live in .github/workflows/:

  • ci.yml — runs the test suite (pytest -W error) on every push to main and on every pull request.
  • weekly-update.yml — regenerates the site JSON in-season. Runs on a cron of 23 5 * 9-12,1 3 (Wednesdays 05:23 UTC — overnight after Tuesday's stat finalization, ET — September through January), and can also be triggered manually (workflow_dispatch).
  • pages.yml — deploys site/ to GitHub Pages whenever a push to main touches site/**, can be triggered manually, and is explicitly dispatched by weekly-update.yml after it pushes fresh data (bot-token pushes don't fire on: push workflows, so the weekly job calls gh workflow run pages.yml itself).

Fail-safe contract: weekly-update.yml generates the site JSON before it commits anything. If the data pull or generation step fails for any reason, the job fails before the commit step runs, so nothing is committed and nothing deploys — the site keeps serving last week's data, with its "data as of" stamp still honestly showing when that data was generated.

Deployed model: the env: block at the top of weekly-update.yml selects the model. It is set to MODEL: transformer with ARTIFACT_ROOT: models/transformer/v1 — the run root, not a through<year> directory; the predictor appends through{last-trained-season} itself. A comma-separated list of run roots deploys a seed ensemble.

One-time setup: these workflows are inert until the repo is pushed to GitHub. Once pushed, enable Pages once under repo Settings -> Pages -> Source: GitHub Actions.

Preseason draft-board refresh: before week 1, run weekly-update.yml manually with the draft input checked. This regenerates only the draft board (--draft, no --week), since the target season has no games yet and requesting its weekly stats would fail; the weekly slate resumes once the season starts (cron or plain dispatch, which use --week auto).

Status

  • Plan 1: data pipeline, scoring, features, eval harness, baselines
  • Plan 2: quantile transformer code complete (CPU smoke-tested end-to-end on real data)
    • Transformer walk-forward artifacts: pending GPU training (see Training on SageMaker Studio Lab)
  • Plan 3: draft board + weekly site, GitHub Actions automation
    • Site pages (draft board, weekly, about) and all three workflows complete
    • First real 2026 draft board generated (xgboost) and committed under site/data/

Remaining user tasks:

  • Create the GitHub remote and push (workflows are inert until then)
  • Enable Pages once: repo Settings -> Pages -> Source: GitHub Actions
  • Train the transformer on Studio Lab GPU (see Training on SageMaker Studio Lab)
  • Flip MODEL/ARTIFACT_ROOT in weekly-update.yml to the trained transformer

About

Floor & Ceiling — NFL fantasy projections: PyTorch quantile transformer, walk-forward evals, self-updating GitHub Pages draft board

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages