HockeyAlpha

Methodology

How every number on this site is built

Two things should be true of any stat before you cite it: you can explain how it was calculated, and you know where it stops being trustworthy. This page covers both for everything HockeyAlpha publishes, including the parts that are currently wrong.

The data underneath

Everything here is derived from the public NHL play-by-play feed and shift charts. Nothing is hand-tracked and nothing comes from a commercial tracking provider.

That feed records discrete events with x/y coordinates: shots (including type, strength state and zone), goals, missed shots, blocked shots, hits, faceoffs, takeaways and giveaways, plus exact shift start and end times for every player. It does not record passes, zone entries and exits as such, puck carries, or any continuous tracking of players and the puck. Every metric below is bounded by that.

The current database holds the complete 2025-26 season: 1,394 games and 163,021 shot attempts with computed xG. Aggregate advanced stats are stored for six seasons, 2020-21 through 2025-26. Shootout attempts are excluded from every shot metric, since a penalty-shot conversion rate has nothing to do with in-play shot quality.

Expected goals

Expected goals assign every unblocked shot attempt a probability of becoming a goal. Ours is a logistic regression fit on our own season of shots rather than borrowed from another public model: 130,000 unblocked non-empty-net attempts containing 8,025 goals.

Distances are measured to the goal at x = 89, so d = sqrt((89 - |x|)² + y²), and the angle is the deviation from straight on. The distance term is deliberately not linear. Goal probability falls off fast in the first twenty feet and slowly after that, so the model carries a square-root term and three hinge terms that let the slope change at 20, 30 and 45 feet.

The model

Empty-net attempts bypass the model and use an empirical distance-tapered rate, since the league converts roughly 51% of them and the geometry works differently with no goaltender. Probabilities are capped at 0.95.

P(goal) = sigmoid(z)

z = -0.373071
    - 0.013932 * distance
    - 0.226725 * sqrt(distance)
    - 0.014151 * max(0, distance - 20)
    - 0.023861 * max(0, distance - 30)
    + 0.006738 * max(0, distance - 45)
    - 0.016202 * angle
    - 0.173844 * (rebound ? 1 : 0)
    + shot type coefficient
    + strength coefficient

shot type (wrist = baseline 0)
    slap        +0.469467      backhand     -0.406192
    snap        +0.294545      deflected    -0.410526
    wrap-around -0.668220      tip-in / bat -0.909669

strength (5v5 = baseline 0)
    power play  +0.225147      penalty kill -0.028406
    other       +0.197389

Where it is limited

No pre-shot movement. The single largest known driver of shot quality is what happened immediately before the shot: whether the puck crossed the slot, whether the goalie had to move laterally, whether it came off a rush. The public feed records none of it. This is the biggest gap between our model and one built on tracking data, and no amount of extra tuning closes it.

No venue adjustment. Shot coordinates historically carried rink-to-rink recording bias. We do not currently correct for it, and we have not yet measured how large the residual effect is in modern data.

Shot type is reported, not measured. Whether an attempt is logged as a snap shot or a wrist shot is a scorer's judgment, and the model leans on those labels.

The rebound term is currently wrong. Its fitted coefficient is negative, which means a net-front rebound scores slightly below the identical clean shot from the same spot (0.180 against 0.207 at roughly seven feet). That contradicts both the literature and hockey sense. The likely cause is our rebound definition being too loose: any attempt within three seconds of a same-team shot on goal qualifies, so a saved point shot followed by a perimeter attempt two seconds later is flagged as a rebound. This is a known defect and it is being fixed.

The on-goal model (used for goaltenders)

Goaltender metrics run on a second logistic model with the same shape, fit only on shots that actually reached the net. This matters: the main model spreads probability across attempts that missed, so summing it over a goaltender's workload undercounts expected goals by roughly 30% and pushes every goals-saved-above- expected figure negative. Any site whose GSAx skews negative league-wide has probably made exactly that mistake.

Where it is limited

It inherits every limitation above except the Fenwick scaling issue. Goals saved above expected is a real measurement rather than a proxy, but it is only as good as the shot-quality model feeding it.

A note on convention: individual, team and setup xG totals are Fenwick, meaning blocked attempts are excluded. That matches how MoneyPuck and Natural Stat Trick report, so the levels are comparable. High danger is defined as distance of 25 feet or lessand an angle of 45 degrees or less. Rebounds use a three-second window off shots that reached the net.

For scale, the model gives a blue-line point shot roughly 0.02, a shot from the slot around 0.13, and a clean net-front chance above 0.20.

Alpha Rating

The Alpha Rating is a single 40 to 99 number per skater, computed separately within two position groups: forwards and defensemen. A player needs 10 games to be rated and 20 games to enter the comparison pool that everyone else is ranked against.

How the number is assembled

Production is scaled against the 95th percentile of points per game in the position group rather than converted to a percentile rank. Percentiles compress everyone at the top into the high nineties, which would make a generational season indistinguishable from a merely excellent one. Scaling to a value keeps that separation, and the cap at 115 stops one outlier from flattening the rest.

Shrinkage pulls small samples toward league average, so a hot fifteen-game stretch cannot outrank a full elite season.

production anchor
  prod = shrink( min(115, (P/GP ÷ p95 of P/GP) * 90) )

four sub-scores, each a blend of percentile ranks
  scoring     = 0.50 goals/GP  + 0.50 ixG/GP
  playmaking  = 0.50 assists/GP + 0.50 PSPL
  transition  = 0.45 ZEIS + 0.35 rush shots/GP + 0.20 xG share
  defense (F) = 0.70 def suppression + 0.30 takeaway:giveaway
  defense (D) = 0.40 def suppression + 0.30 blocks/60
                + 0.30 takeaway:giveaway

small-sample shrinkage, applied to every component
  shrink(v) = 50 + (v - 50) * GP / (GP + 12)

composite
  forwards   = 0.40 prod + 0.27 scoring + 0.23 playmaking
               + 0.06 transition + 0.04 defense
  defensemen = 0.18 prod + 0.12 scoring + 0.14 playmaking
               + 0.22 transition + 0.34 defense

rating = 40 + 59 * (min(100, composite) / 100)

Where it is limited

It is production-anchored on purpose. Points per game carries 40% of the forward composite. The event-derived proxies flavor the number rather than drive it, because they carry a known bias against puck-dominant players who accumulate giveaways by handling the puck constantly. The sub-score bars on every player page show those proxies honestly, unweighted.

Defensemen are underrepresented at the top. Seven of the top fifty overall are defensemen, against roughly a third of skaters. The highest-rated defenseman sits around eighteenth overall. The ordering within the defense group is sound, but comparing a defenseman's rating directly against a forward's will understate the defenseman.

It inherits the proxies. Transition and defense sub-scores are built on ZEIS, PSPL and defensive suppression, so every limitation listed below flows upward into the rating.

On whether the output means anything: the top of the board is McDavid, MacKinnon, Celebrini, Draisaitl, Kucherov and Pastrnak, and the bottom of the rated pool is fourth-line grinders and enforcers. Both ends landing where a hockey person would put them is weak evidence, but it is the right kind of weak evidence, and it is checkable by anyone.

Contract valuations

Every contract on the site is graded against a modeled market price rather than against other contracts directly. The question being asked is: given how this player performed, what would the open market pay them today? The gap between that and their actual cap hit is surplus value.

The market curve

Expected price rises faster than linearly with rating, because the top of the market is scarce. Above the elite threshold a further premium applies, which is why generational players model above the largest deals currently signed.

Comparable players are found by nearest-neighbor search over rating, the four sub-scores and usage, within the same role group.

skaters, as a share of the $95.5M cap ceiling
  span = 47 (forwards) or 40 (defensemen)
  t    = clamp((AlphaRating - 52) / span, 0, 1)
  pct  = 0.9 + K * t^1.4          K = 14.6 F, 12.6 D

  superstar premium above rating 90 (F) / 88 (D)
  pct += ((rating - kick) / (99 - kick)) * 4

  expected cap hit = max(0.85, pct / 100 * 95.5)

goaltenders, who have no Alpha Rating
  workload = min(1, GP / 55)
  expected = clamp(1.1 + 4.4 * workload + 0.16 * GSAx,
                   0.85, 12)

grade = expected - actual cap hit
  A+  >= +4.0     C   >= -0.75
  A   >= +2.0     D   >= -2.5
  B   >= +0.75    F    < -2.5

Where it is limited

The curve is anchored, not regressed. Its shape was fitted by hand to plausible market anchors rather than estimated from actual contract data. It is labeled beta on the site for that reason. A proper version would regress cap hits on performance across many signings.

It ignores everything except performance. Term, age, signing bonuses, no-move and no-trade clauses, restricted versus unrestricted status, and crucially the year the deal was signed all go unmodeled. A star on a contract signed four years ago grades as a bargain partly because the cap has risen since, not because the team was clever. Read the grades as a performance-to-price ratio, not as a verdict on the front office.

The goalie curve is cruder. With no Alpha Rating to lean on it uses only workload and goals saved above expected, so it inherits every limitation of the xG model and adds fewer inputs.

The ceiling is hardcoded at the 2025-26 upper limit of $95.5M and needs updating each summer.

Cap data: CapWages, refreshed weekly.

Structural Event Engine

The engine produces 29 sequence-derived metrics across six groups: general offense, playmaking sequences, offense types, zone entries, defensive-zone retrievals and exits, and forechecking. It qualifies skaters at 700 or more even-strength minutes.

The idea is simple. The feed will not tell you who passed to whom, but it timestamps everything, so proximity in time stands in for a connection between players. If a teammate shoots within about three seconds of a player's possession event, that registers as a setup, with tighter two-second windows for one-timers and deflections and variants for location and zone.

The possession primitive

Every metric built this way is a proxy for something the feed does not measure. That is stated on the metric itself throughout the site, not just here.

possession event = a shot, a takeaway, or a faceoff win

setup = teammate shoots within 3s of a possession event
one-timer setup / deflection setup = within 2s
entry started = a neutral or defensive zone possession event
                is followed by an offensive-zone sequence within 6s

Where it is limited

Clean puck movers are invisible. Those three event types are the only way the feed knows a player touched the puck. A player who receives a pass and moves it on without registering a shot, a takeaway or a faceoff win does not exist to this engine. Setup numbers therefore favor players who shoot, who force turnovers, and who take draws, and they understate pure distributors.

The faceoff leg distorts the entry metrics. Winning a defensive-zone draw is genuinely a possession event that can start a zone entry, but it is so common for draw-taking centers that it dominates. The Entries Started board is currently led by defensive-zone faceoff specialists rather than by transition drivers, which is an artifact of the definition rather than a finding about hockey. We are splitting draws out.

Proximity is not causation. A teammate shooting within three seconds of your takeaway does not prove you created the chance. Across a season the noise largely averages out, but on any single sequence the credit may be undeserved, and busy shifts generate more coincidental credit than quiet ones.

Takeaways and giveaways are judgment calls. They are logged by human scorers and have historically varied between buildings. We do not adjust for that.

Event-derived proxies

ZEIS — transition

A weighted count of the events that move play up the ice, per game, net of the turnovers that give it back.

ZEIS = ( 2.0 * rush shots
       + 1.5 * offensive-zone takeaways
       + 1.0 * defensive-zone takeaways
       + 0.5 * neutral-zone takeaways
       - 2.0 * defensive-zone giveaways
       - 0.5 * neutral-zone giveaways ) / GP

rush shot = an attempt within 8s of a located event
            in the shooting team's neutral or defensive zone

Where it is limited

Raw giveaway counts punish players who carry the puck most, so the best transition players in the league are pushed down by the thing that makes them valuable. The Alpha Rating compensates by blending rush volume and offensive involvement into its transition sub-score, but ZEIS on its own retains the bias. The eight-second rush window is also a judgment call, and the metric is sensitive to it: widening it from four seconds took one player from 5 rush shots on the season to 160.

PSPL — playmaking

The expected goals a player generates for teammates, rather than the assists they are credited with.

PSPL = (setup xG / GP) * 10

setup xG accrues when, within 3 seconds of
  (a) the player's shot on goal, or
  (b) the player's offensive-zone takeaway,
a different teammate takes an unblocked shot.
The xG of that teammate's shot is credited.

Where it is limited

It captures rebound creation and turnover-driven chances, which is a real but narrow slice of playmaking. The classic setup pass, a clean feed to an open teammate, generates no recorded event for the passer and so contributes nothing. It also currently ranks at least one defensive defenseman inside the top ten, which points at the offensive-zone takeaway leg crediting puck retrievals as creation. That is under investigation.

Defensive suppression

Defensive events that end an opponent's possession, per game, net of the ones that hand it back.

Def Sup = ( blocks
          + 1.5 * defensive-zone takeaways
          - 1.5 * defensive-zone giveaways ) / GP

Where it is limited

Blocks and takeaways are counting events that reward players who spend more time defending, which correlates with playing on a worse team. Nothing here measures positioning, gap control or the chances a player prevented by never letting them start.

GSAx and GWD — goaltending

Goals saved above expected is the difference between the quality of shots a goaltender faced and the goals they actually allowed. Goalie Workload Difficulty summarizes how hard the job was.

GSAx = (expected goals faced, on-goal model) - goals against

GWD  = 100 * ( 0.50 * avg xG per shot / 0.09
             + 0.30 * high-danger share / 0.25
             + 0.20 * lateral movement load / 40 )

Where it is limited

GSAx is a real measurement, not a proxy, but it is only as accurate as the shot-quality model behind it, which cannot see pre-shot movement. GWD is a workload-difficulty index built from three normalized components, and the divisors are league-average anchors chosen by us rather than derived, so treat it as an ordering rather than a unit.

Percentiles and qualification

Almost every bar on the site is a percentile rank inside a position group, so 50 is exactly league median and 90 means top ten percent. This lets a faceoff percentage and a cross-slot rate sit side by side and mean the same thing.

Qualification thresholds differ by surface, deliberately:

  • Alpha Rating: 10 games to be rated, 20 games to enter the pool
  • Leaderboards: 30 games
  • Structural Event Engine metrics: 700 even-strength minutes
  • Faceoff metrics: centers with 100 or more draws

Those floors are a real limitation on rate statistics. A 30-game minimum still lets a partial season top a per-game leaderboard, and we are raising it.

Abbreviations

Short forms used across the site. Every metric also carries a hover definition on the page where it appears.

xG
Expected goals. The probability a given shot attempt becomes a goal.
iXG
Individual expected goals. The sum of xG on a player's own attempts.
xG share
A player's iXG as a share of their team's xG in games they played.
CF%
Corsi for percentage. Share of all shot attempts, blocked included.
FF%
Fenwick for percentage. Share of unblocked shot attempts.
xGF%
Expected goals for percentage. Share of on-ice expected goals.
HDCF%
High-danger chances for percentage. Chances inside 25 ft and 45 degrees.
GSAx
Goals saved above expected. Expected goals faced minus goals allowed.
GWD
Goalie workload difficulty. A composite index of how hard the job was.
ZEIS
Zone Exit/Entry Impact Score. Our transition proxy, per game.
PSPL
Pre-Shot Pass Lethality. Our playmaking proxy, expected goals created for teammates.
RRΔ
Cross-slot shots. Attempts within 2s of a same-team attempt from the other side of the royal road, the net-to-net line.
ZEUP
Pressure escape rate. How often the player's team escapes defensive-zone pressure and counters within 15s.
PRI
Second-chance touches. Follow-up attempts within 3s of a teammate's unscored shot.
QoC / QoT
Quality of competition and of teammates. Who a player lines up against and with.
TOI
Time on ice. EV TOI is the even-strength portion.
GP / P/GP
Games played, and points per game.
PP / PK
Power play and penalty kill.
OZ / NZ / DZ
Offensive, neutral and defensive zone.
5v5
Five skaters a side with both goaltenders on the ice.
Corsi / Fenwick
All shot attempts, and attempts excluding blocked shots.
AAV
Average annual value. A contract's salary-cap hit.

What we have not tested

The honest ledger. These are open, not hidden, and they are the reasons to discount what you see here.

  • The xG model has not been validated out of sample. Its calibration checks were run on the same season it was fit on. Worse, a logistic regression is calibrated on its training data by construction, and per-category agreement is forced by the fitting procedure, so those checks are not evidence of accuracy. A genuine holdout, scoring earlier seasons the model never saw, is in progress.
  • The proxies have never been tested for repeatability. For a derived metric the question that matters is whether it correlates with itself season over season for the same player. If it does not, it is measuring noise. We have six seasons loaded and have not yet run it.
  • The venue effect has not been measured. We do not adjust for building, and we have not quantified what that costs.
  • The rebound term is a known defect and is described in full above.
  • Nothing here has been externally audited. Every check described on this page was run by the same person who wrote the models. Artifacts survive that process routinely.

If you find something wrong, that is genuinely useful. Mail support@hockeyalpha.com and it will get looked at.