NHL Player Value Model
A comps based model that prices every active NHL skater, then a second model that decides whether a trade built on those prices would get accepted.
Open the live site- Stack
- Python, scikit-learn, Next.js, Postgres, Railway
- Backtest
- 735 signings, 2020 to 2026
- Status
- Live, updated nightly
How the model works
For every active NHL skater, the model finds the closest comps who already have a verified contract and averages their AAVs. Similarity is a weighted distance over performance score, points per 60, powerplay points, and age. Comp weights are position specific: forwards are matched offense first, defensemen defense first.
UFA contracts get extra weight in that average. UFA prices are what teams pay on the open market, without arbitration or RFA leverage. RFA and mid contract deals still count, just less.
The pool excludes contracts that do not reflect market value. Entry level deals are capped by rule. Buyouts are artificially low. Injury seasons distort the rate stats and get filtered out. Every AAV is normalized against the cap ceiling of its signing year before it enters the comp pool, so a $7M deal signed under an $81.5M cap is compared fairly against one signed today.
The model prices the upcoming season. It blends prior and current production and paces both to a full 82 games.
What the backtest says
The model is graded against every real signing it can reconstruct: 735 contracts signed between 2020 and 2026, each priced using only the data available before the deal was signed.
- Correlation 0.811 between predicted AAV and the contract the player actually signed.
- Mean absolute error $1.19M, RMSE $1.5M.
- 49% of contracts land within $1M of the real number, 83% within $2M.
- Bias +$0.55M. The model runs high. It pays players more than the league does, on average.
Where it breaks
The error flips sign with contract size. On deals under $3M the model's median error is +$1.1M (242 contracts). On deals between $8M and $12M it is -$0.9M (74 contracts). It overpays the bottom of the market and underpays the top.
This comes from how comps work. A fringe player has hundreds of near neighbors and gets pulled up toward the middle of the pack. A star has almost no comparable contracts, so the average of his closest matches sits below what a team would pay to keep him. To correct for it, the top of the range follows a saturating curve fit to the top of the market, with the knee anchored at the highest UFA deal.
I report bias per season instead of one blended number, because the cap changed a lot over those six years and a single average hides that.
Trade Lab
Trade Lab asks whether a trade built from those prices is one a real GM would sign. It takes a proposed deal and grades it from both sides.
Player value comes from the contract model, but acceptance takes more. A team selling a franchise player wants a return that scales with his tenure and pedigree as well as his dollar value, so the model marks down deals a team would turn down on principle even when the values line up. Draft picks are priced from a live catalog of every traded pick through 2033, with conditional picks resolved by what happened.
The trade model is scored on whether it can tell a real return from a deliberately shortchanged version of the same return. Fitting past trades alone would not test this, since every trade in that data was accepted by both sides.