What is inside our NHL predictions, which parts we tested and rejected, and how every pick is graded in public. Educational analytics, not betting advice.
Checked against the model code on November 15, 2026.
Game results, schedules, rosters, box scores, play-by-play, standings and player stats come from the NHL’s public API. We use it rather than scraping sites whose terms prohibit derivative tools. Injury reports come from ESPN, with an optional second feed. Betting odds are used for one purpose only: to compare our numbers with the market. The full list, with refresh times, is on the data sources page.
The score model is a bivariate Poisson model with the Dixon-Coles correction, a standard way to model low-scoring sports. Each team gets an attack rating and a defence rating, fitted by weighted maximum likelihood on completed regular-season and playoff games. A team’s expected goals in a game are the league average, plus a home-ice effect for the home side, plus its own attack, plus the opponent’s defence (on a log scale).
The score model refits from completed games on every run, so there is no stored model file that can go stale.
The second layer is a classifier trained on a versioned table of dozens of pre-game features per game: rolling ten-game goals for and against, shooting and save percentages, power-play and penalty-kill rates, rest and travel, goalie form, injury impact, Elo ratings, season points percentage, ten-game shot share and ten-game expected-goals share.
Training is strictly time-ordered. We never use random splits for sports data, because a random split lets a model train on games played after the ones it is tested on. A classifier does not go live because it scores well once. It has to pass a gate:
If nothing passes, the score model keeps serving. Which classifier serves, if any, can change at any retrain, which is why we publish the gate and not just the winner.
An early version of the features read season-long totals, such as a team’s win percentage and head-to-head record, from summary tables that already included the game being predicted and games after it. The model looked better than it was. We rebuilt those features from the games table with a strict “played before this game” filter, and the rule is that models trained on the old values are never mixed with the new ones. A later fix changed how goalies are picked (the team’s own game logs, not today’s roster) and when injuries count (open on the game date, not today’s snapshot). A hockey model that has never found a leak like this has probably not looked hard enough.
We compare our probabilities with the no-vig consensus price of Canadian-market sportsbooks, as a benchmark. On 2026-11-12, on 92 test games with odds, the consensus price scored a log-loss of 0.545 against 0.611 for our classifier, a wide gap in the market’s favour. Odds exist only for 2026-27, so a few hundred games can fit one number and not much more.
So the served probability can be a blend of the model and the market on the log-odds scale, with the market’s weight capped at 0.75 so the model always contributes. The fit on all 92 games chose 1.00 (the market alone), while the only out-of-sample fit chose 0.65, which is why the cap exists. When a blend is used, the prediction shows a market-consensus factor so the shift is visible. This is analysis of how our model compares with a better-informed price. It is not a recommendation to bet.
The playoff odds page simulates the rest of the regular season 10,000 times. Every remaining game is priced by the production score model. Each simulated season first shifts every team’s strength by a random amount, because a model that is calibrated one game at a time becomes overconfident over a whole season if its ratings are treated as exactly known. Teams are then ranked with the NHL’s format and tiebreakers: the top three in each division and two wild cards per conference, by points, regulation wins, regulation plus overtime wins, wins, goal differential, then a random draw. The head-to-head tiebreaker is not modelled yet, and goal differential uses its current value.
Every prediction is graded after the game ends, and the accuracy page updates nightly. A pick is the side with a win probability of 50% or more, and an exact 50% goes to the home team, because a hockey game always has a winner. We report:
We keep the season’s numbers on the accuracy page, not here, so they are always current. Treat early-season records with care: 100 graded games carry a standard error of about 5 percentage points on a hit rate near 60%, so a lead over a baseline can be real and still not settled.
Every pick is graded after the game against a coin flip and an “always pick the home team” baseline, and the season record, calibration and weekly report cards are public on the accuracy page. Early-season samples are small, so a lead over a baseline can be real without being settled.
A Dixon-Coles score model estimates each team’s expected goals, and a classifier trained on past games estimates the home team’s win probability. A classifier serves live only if it beats a baseline and the score model in at least three of four walk-forward test periods; otherwise the score model serves.
No. It is educational analytics, not betting advice. Betting odds are used only as a benchmark for how the model compares with the market, and a probability is never presented as a recommendation to bet.
By simulating the rest of the regular season 10,000 times, pricing every remaining game with the same score model and adding randomness to each team’s strength so the odds are not overconfident. Teams are ranked with the NHL’s format and tiebreakers.
The NHL’s public API for games, players and standings, ESPN for injury reports, and odds from licensed providers for benchmarking only. The data sources page lists each provider and how often it refreshes.
For educational/analytics purposes only — not gambling advice