How our CBB projections work
By George Boyle · Published 2026-09-26 · 6 min read
Every projected score, spread and total on the Matchups page comes from one model: expected possessions times each team's opponent-adjusted points per possession, plus a home-court term. Before it was allowed to show a single number publicly, it had to pass a pre-registered test against a college basketball season it had never seen.
What the model actually computes
The build is deliberately simple: possessions per team, times each side's points per 100 of those possessions, plus a home-court adjustment. Possessions are estimated the standard tempo-free way — field-goal attempts minus offensive rebounds plus turnovers plus a fraction of free-throw attempts — averaged across both teams in a game. Points per 100 possessions ('efficiency') is opponent-adjusted: a team's offensive number is stripped of who it has played by comparing it, game by game, against what the opposing defense has allowed everyone else.
Home court is a single points-per-100-possessions constant applied to whichever side is truly at home (zero at a neutral site). Everything the model knows about a team before its season starts comes from one place: last season's final adjusted rating, regressed most of the way back toward the D1 average. A team with no D1 history at all — a program moving up a level — starts near the bottom of the pack, because that is where teams in that position have historically finished.
How it was tested
The model was fit on three seasons — 2022-23 through 2024-25 (2021-22 supplied only the very first prior, for teams entering 2022-23) — and then locked. Every constant it uses, including the home-court number and how much weight a new season gives to last year's rating, comes from that fitting window alone.
Before a single number from the 2025-26 season was looked at, the test it had to pass was written down: a set of thresholds comparing its projected spreads and totals to what actually happened, and separately to Pinnacle's own closing spread and total for the same games — the most accurate publicly available estimate there is. The rule was explicit up front: this model does not see the market and is not expected to beat it. The bar was simply to be close, not to be better.
What it had to clear
Six checks, all measured on the full 2025-26 season, D1-vs-D1 games with a Pinnacle line: how far off the projected spread was compared with how far off the closing line was; the same for totals; whether the projection was systematically biased toward one side; whether it beat two much simpler baselines; and whether its win probabilities were honest — when it says a team has a 70% chance to win, does that team win about 70% of the time.
| Check | Result | Threshold | Passed |
|---|---|---|---|
| Spread error vs. the close, full season | +0.36 pts | ≤ 1.00 pt | Yes |
| Spread error vs. the close, from Jan 1 on | +0.13 pts | ≤ 0.75 pt | Yes |
| Total error vs. the close, full season | +0.36 pts | ≤ 1.50 pts | Yes |
| Bias (signed margin / signed total error) | +0.22 / +0.01 pts | ≤ 0.50 / ≤ 1.00 pts | Yes |
| Beats two simpler baselines, spread and total | lower on both | strictly lower | Yes |
| Win-probability calibration (10 deciles) | 2.2% | ≤ 3.0% | Yes |
The two baselines it had to beat
The first baseline froze every team's rating at its preseason number for the entire season — no in-season updates at all — and projected a spread error of 10.45 points and a total error of 15.35. The second used raw season-to-date efficiency and tempo with no opponent adjustment whatsoever, and projected 10.76 and 14.98. The full model's 9.32 and 13.76 beat both baselines, on both measures.
Early season vs. conference play
Split by time of year, the gap between the model and the close is wider in November and December than it is from January on. That is expected: two months in, most teams' ratings still lean heavily on last year, while the closing line has already absorbed real games. By January, both are working off a full season of data and the gap narrows to a third of a point.
| Window | Spread error (ours / close) | Total error (ours / close) |
|---|---|---|
| Nov–Dec | 10.01 / 9.29 pts | 13.92 / 13.41 pts |
| Jan 1 on | 8.90 / 8.76 pts | 13.66 / 13.39 pts |
| Full season | 9.32 / 8.97 pts | 13.76 / 13.40 pts |
A bias that flips sign with the calendar
One thing the season split also showed: the model's small bias flips direction between the two windows — it slightly underrates home teams early and slightly overrates them later. That pattern, and a full attempt to fix it, is its own study: see "Home court advantage in college basketball" below.
Checked against an outside source
As a sanity check outside the model's own test, its opponent-adjusted ratings were compared against CollegeBasketballData's independently computed adjusted efficiency margins for the same season. The two rank teams almost identically — a rank correlation of 0.99 — which is reassurance that the model is measuring the same thing other tempo-free systems measure, not something idiosyncratic to its own fitting choices.
Method
One module holds every piece of this — the daily production build and the season replay used for this test both call the same code, so the number that gets tested is the number that ships. Efficiency and tempo are each fit by a weighted ridge regression that shrinks every team toward its preseason prior, refit day by day in a strict walk-forward replay: a game on any date is projected using only games played before that date, never anything from the date itself or later.
The fitted constants: home court worth 2.877 points per 100 possessions per side, a preseason team's rating pulled 80% of the way back toward the mean, and a projection-error standard deviation of 11.61 points (the number the win-probability conversion uses). All of them came from a grid search over the three training seasons only — the held-out season was never used to choose anything, and can only be looked at once per pre-registered amendment.
What this does not claim
Beating the market is not the test and was never the goal — the model does not see the market at all. Its early-season numbers are its weakest, by design: it leans on last year's rating until this year's results accumulate. And it does not know about injuries; ESPN publishes no college basketball injury feed, so the Matchups page shows recent playing time instead of an injury designation.
Written by George Boyle, who builds The Sport Stack — the models, the ratings and these write-ups. Corrections and questions: hello@thesportstack.io. Who runs this.