walrusquant/sports-analytic-skills

simulation-sports

Simulate game and season outcomes from user-supplied probabilities or ratings, summarize uncertainty, and test sensitivity to assumptions.

View source
Original skill document

Rendered from the source repository. Headings, examples, code, tables, links, and referenced images are preserved.

Simulation (Sports)

Overview

Turn game-level probabilities or ratings into distributions:

  • win counts across a declared full-season or remaining-schedule input
  • make-playoff-style tallies
  • matchup series outcomes
  • uncertainty around a point forecast

Simulation does not create accuracy the base model lacks — it propagates uncertainty from a base model under stated assumptions.

Work from user-supplied pre-event probabilities or ratings and a documented schedule.


When to Use This Skill

Use when:

  • Season win-total distributions
  • Playoff-path / remaining-schedule projections from a model
  • Matchup simulations from ratings or predictive probabilities
  • Stress-testing uncertainty around a point forecast
  • User says “project the standings” or “simulate the season”

Do not use when:

NeedGo instead
No underlying probability/rating model yetbuild one first (ratings-strength-models, predictive-modeling)
Single-point prediction is enoughmodeling skills only
Discrete-event engineering sims unrelated to sports outcomesout of scope
Calibration of the base probscalibration-check first

Installation

The bundled simulator requires pandas and NumPy:

bash
python -m pip install pandas numpy

Parquet input also needs pyarrow or fastparquet.


Required Inputs

  • Base model: pre-game win probs or as-of rating differentials
  • Schedule / remaining games (one row per game, not doubled panel)
  • n_sims and seed
  • Dependence assumption (independent games vs path-dependent updates)
  • Sport + season window

Workflow

  1. Define the object being simulated (game, series, rest-of-season, full season).
  2. Choose the base model (logistic probs, Elo expected score, etc.).
  3. Confirm base probs are at least usable (calibration-check if quoting percents).
  4. State dependence assumptions (independent games? injury freeze? home effects?).
  5. Fix seeds and n_sims for reproducibility.
  6. Build as-of inputs (Elo table or probability table).
  7. Run Monte Carlo on home rows once per game.
  8. Summarize distributions (mean, median, p05/p95, histogram) — not only means.
  9. Sensitivity-check K, home advantage, independence assumptions.
  10. Report seeds, n_sims, assumptions, limits, repro commands.

Base Model Inputs

InputSource
Pre-game win probspredictive-modeling, statistical-modeling, baseline-models
Elo / rating diffsratings-strength-models or a documented rating artifact
Scheduleuser-owned event table with stable IDs and roles

Convert rating diff to probability if needed:

text
P = 1 / (1 + 10 ** (-elo_diff / 400))

If a rating artifact must be converted, document the scale and whether home advantage is already included. Prefer a probability column whose calibration has been evaluated on forward holdouts.

Runnable Schedule-Win Simulator

The helper expects one row per simulated event after filtering, with a pre-event win probability for the focal team:

text
season,game_id,is_home,team,opponent,win_probability
bash
python /path/to/simulation-sports/scripts/season_win_sim.py \
  --input schedule_probabilities.parquet \
  --season 2024 --n-sims 5000 --seed 7 --threshold 10 \
  --out season_win_sim_2024.json

It filters to is_home == 1, requires unique game_id, simulates binary outcomes from the supplied probabilities, aggregates participant wins across those rows, and writes mean and central quantiles plus optional threshold probabilities. It does not add wins from completed games omitted from the input. Therefore its output is a full-season total only when the supplied rows cover every game in that season. For a remaining-schedule projection, add each team's known completed wins outside this helper and label that external step. The JSON makes this scope explicit in win_count_scope and in canonical fields such as mean_wins_in_supplied_games; ambiguous legacy aliases remain only for backward compatibility.

Game-level only

Always simulate one declared perspective per event. Never treat home and away rows from a symmetric panel as independent games.


Design Choices

Independence

Default script treats games as conditionally independent given pre-game probs. That understates variance if injuries/momentum couple games. State the shortcut.

Updating ratings inside the season sim

  • Simple mode: freeze pre-game probs from historical as-of table (reproducible evaluation)
  • Advanced mode: update Elo inside each simulated world (path-dependent)

Start simple.

Schedule constraints

Season sims must use the real schedule graph. One game once.

Calibration prerequisite

If base probs are miscalibrated, fix/note calibration first (calibration-check).

Read simulation_assumptions.md before fixing event dependence, schedule, tie, update, or missing-event rules. Read sensitivity.md when choosing perturbations and deciding whether conclusions are robust.


Hard Constraints

  1. Simulation cannot invent accuracy the base model lacks.
  2. Report seeds, n_sims, and assumptions every time.
  3. Do not present simulated means as guarantees.
  4. Respect schedule constraints.
  5. If base probs are miscalibrated, say so.
  6. Never double-count home and away panel rows as two games.
  7. Sensitivity is required before strong distribution claims.

Anti-Patterns

  • Simulating with an unvalidated coin-flip model dressed as analysis
  • Huge n_sims hiding bad assumptions
  • Showing only expected wins with no spread
  • Using both home and away panel rows as two independent games
  • Silent dependence assumptions
  • Quoting playoff odds from uncalibrated 0.55-ish probs

Reporting Template

text
Simulation: wins across supplied full-season / remaining-schedule rows
Base model: Elo→prob (K=…, home_adv=…)
Season:
n_sims: … seed: …
Dependence: independent games | path-dependent rating updates
Outputs: mean and p05/p50/p95 wins in supplied games by team
Sensitivity:
Limits:
Reproduce:

Output Contract

Done means:

  • [ ] Base model named and sourced
  • [ ] n_sims + seed reported
  • [ ] Dependence assumption stated
  • [ ] Distribution summaries (not only means)
  • [ ] Sensitivity note present
  • [ ] Repro commands present

Worked Example

bash
python /path/to/simulation-sports/scripts/season_win_sim.py \
  --input schedule_probabilities.parquet \
  --season 2024 --n-sims 5000 --seed 7 --threshold 10 \
  --out season_win_sim_2024.json

Report: “Independent-game Monte Carlo from held-out-calibrated pre-event probabilities; mean and central quantiles by participant; simulation uncertainty does not include all roster, injury, schedule, or model uncertainty.”


Bundled Resources

references/

FileContents
simulation_assumptions.mdassumption checklist
sensitivity.mdwhat to stress-test

scripts/

FileContents
season_win_sim.pyMonte Carlo participant win counts across supplied pre-event probability rows

Related Skills

NeedSkill
Ratingsratings-strength-models
Predictive probspredictive-modeling
Calibrationcalibration-check
Reportingresults-reporting
Rating constructionratings-strength-models

Quick Command Card

bash
python /path/to/simulation-sports/scripts/season_win_sim.py \
  --input schedule_probabilities.parquet \
  --season 2024 --n-sims 5000 --seed 7 --threshold 10 \
  --out season_win_sim_2024.json

from this repository

More skills

All skills