Quantitative sports research · event-contract modeling · 2026 · Research platform (paper trading only)
Teams and historical games pulled per league from a sports-data API, staying within its free tier of 5 requests a minute.
A multi-sport schema from day one, so adding a league is configuration, not a rewrite. Migrations are managed with Alembic.
Computed chronologically over every completed game, with sport-specific settings (see below).
Leak-safe features built only from information available before each game.
Five models per league, trained and selected on a strict time-based split.
Model probabilities vs. event-contract prices: a read-only Kalshi feed for live markets, a synthetic market for development, and historical Polymarket prices for backtests.
Model-minus-market disagreement, bucketed, to test whether bigger disagreements actually win more often.
Simulated positions only, opened when the model's edge clears a threshold and settled automatically.
Model lab, games and edges, market matching and paper-trading views with a league switcher, plus a daily research report.
The Elo engine follows the approach FiveThirtyEight published: a home-field adjustment, a margin-of-victory multiplier, and a one-third regression toward the mean each new season. The constants, though, were tuned per sport on validation seasons and never on the test season.
Two findings came straight out of that search. The standard 100-point home advantage was roughly 4× too high in every sport; accuracy degraded steadily past about 25–50 points. And the best K-factor tracked season length: long seasons like MLB's ~162 games need small updates per game, while the NFL's ~17 games need large ones.
| League | K-factor | Home advantage |
|---|---|---|
| MLB | 5 | 25 |
| NBA | 10 | 25 |
| WNBA | 15 | 25 |
| NFL | 30 | 25 |
Untuned default was K = 20, home advantage = 100.
Features are home-minus-away differences built only from games already played, so nothing from the future leaks into a prediction. They include:
Each league trains a one-feature season-win% logistic model, a closed-form Elo model, a 16-feature logistic regression, an XGBoost model calibrated with isotonic regression, and an ensemble. The ensemble's weights are fit on validation data by minimizing log loss, constrained to be non-negative and sum to 1, rather than hand-picked.
| League | Best model | Test Brier | Note |
|---|---|---|---|
| NBA | Ensemble (51% XGB / 27% Elo / 22% logistic) | 0.2091 | Blending beat every individual model |
| NFL | Ensemble (85% Elo / 15% XGB) | 0.2342 | Small sample favors simple signals |
| MLB | Ensemble (63% XGB / 24% logistic / 8% win% / 5% Elo) | 0.2467 | Essentially tied with season win% |
| WNBA | Elo | 0.2169 | Ensemble within 0.0006 but didn't beat Elo |
Brier score: lower is better; 0.25 is a coin flip.
Live market prices come from a read-only Kalshi integration, with each game matched to its market. Historical backtests replay Polymarket prices. The fee model for that replay is zero, because standard Polymarket sports markets charge no taker fee, and the limitation is stated plainly: slippage, order-book depth and market impact are not modeled.
A simulated position opens only when the model's probability beats the market's by at least 3 percentage points, using a fixed $100 simulated unit. Edges are then bucketed (under −10% up to over 10%) to check whether larger disagreements actually win more often, which is the real test of whether the model knows something the market doesn't.
Implemented and live in the pipeline: NBA, NFL, MLB and WNBA. Researched and planned: NHL, NCAA basketball, NCAA football, soccer and other sports.