Case study · Quantitative research

Quantitative Backtesting Engine

An event-driven backtester for NBA betting markets, written from scratch — no backtesting frameworks, no scikit-learn in the model path. 24,440 games, 19 seasons, and a result that says the strategy does not work.

  • Personal project
  • Python · NumPy · SQLite
  • 2008–2026 · 24,440 games

The problem

Most public "betting model" projects report a profitable backtest. Almost none of them are trustworthy, because the same handful of mistakes inflates every result: the model peeks at data it wouldn't have had at bet time, the strategy's parameters are tuned on the same seasons used to score it, and the sportsbook's commission gets quietly ignored. The interesting engineering problem isn't building a model — it's building a harness where those mistakes are structurally impossible, and then reporting whatever it says.

The approach

Architecture

Backtesting engine pipeline Sources odds · box scores Point-in-time store as-of queries only Features no lookahead Models logistic · ridge Devig + edge fair price vs. model Sizing flat · capped Kelly Walk-forward ledger ROI · CLV · drawdown · bootstrap CI

What it found

On the single-shot holdout season, both markets lost money: −5.64% ROI across 923 spread bets and −8.61% across 954 totals, with 90% bootstrap intervals lying entirely below zero. That is a falsifiable negative result, and it is the honest headline: the NBA closing line is efficient against public box-score information.

Three follow-ups made the negative result mean something:

Making it fast

Proving it correct

Stack

← Back to all projects