athletevalue
What an NCAA men's basketball player's wins are worth to his school, and what a published roster budget would pay him. A Python package and CLI that rates players from every lineup they played, converts impact into wins and into the revenue schools attribute to basketball in federal filings, and sets that against an allocation of reported roster budgets. Every number carries an interval and a stated basis.
What the price side is. No public dataset records what individual college basketball players are paid. The "roster market value" this package prints is an allocation: a published conference-tier average budget, spread across a roster by role and rating. It contains no information about any player's contract and is labelled a scenario for that reason. A model that learns pay from disclosed deals is included but ships dormant, because there are no public deals to train it on.
No pay data. Every output is a research estimate built from public game data and public filings. None of them states what a player is paid, and none should be quoted as a salary. See DISCLAIMER and PRIVACY.
Install
pip install athletevalue # or: uv add athletevalue
Python 3.12 or later. The first valuation downloads about 500 MB of public data for
16 seasons and parses 15 years of EADA spreadsheets; allow several minutes and about
5 GB of memory for a season fit (7 GB with --cv). Later runs read the cache.
athletevalue cache-path prints the cache location.
Quick start
athletevalue value "Player Name" --season 2026 --team "School"
The example below is a synthetic player on a synthetic season, produced by
scripts/readme_example.py; the README does not name real athletes.
A. Guard · State U (Example Conf) · 2025-26 · starter
Athletic impact +4.6 /100 80%: +0.9 to +8.3 ▲ estimated
offense / defense +2.6 / +2.0
Wins above replacement 0.6 80%: 0.2 to 1.2 ○ scenario
replacement bench median (-0.3/100); under nba convention 0.9 / pooled 0.6
Program value $62k 80%: $13k to $160k ○ scenario
win revenue, this season $31k 80%: $8k to $55k ○ scenario
bid revenue, this season $9k 80%: $1k to $29k ○ scenario
tournament units $23k 80%: $3k to $76k ○ scenario
with next season $83k 80%: $18k to $206k ○ scenario
Roster market value $1.47M 80%: $485k to $2.54M ○ scenario
Surplus -$1.40M 80%: -$2.42M to -$468k ○ scenario
Among paid teammates both above median (relative to team medians)
Drivers
+ on-court impact ranks 1 of 72 rated players
~ box-score prior +3.4 per 100; own possessions moved the rating +1.1
+ on the floor for 58% of team possessions
~ team went 10-4, net rating +12.1
+ program reports $12.00M basketball revenue (D1 median $7.00M)
+ Example Conf roster budget tier: power (published average, collectives included); the House cap for direct revenue sharing across all sports is $20.50M
Price basis: allocation. Status: ● reported ◆ derived ▲ estimated ○ scenario
As of 2026-09-17 · games through 2025-12-29 · model mbb-v0.4.0
No contract data is used. The market value spreads a published conference-tier budget across the roster by role and rating.
from athletevalue import api
valuation = api.value_player("Player Name", season=2026, team="School")
print(valuation.summary())
valuation.war.value, valuation.war.lower, valuation.war.upper
table = api.value_team("School", season=2026) # polars DataFrame, one row per player
Other commands:
| Command | What it does |
|---|---|
athletevalue fit --season 2026 [--cv] [--no-prior] |
Fit ratings and print the top players |
athletevalue validate --season 2026 |
Check the fit against published references |
athletevalue team "School" --season 2026 |
Value and allocated price for a roster |
athletevalue market-fit --labels deals.csv |
Fit the market model on deals you supply |
athletevalue assumptions |
List every model constant, its value, basis and status |
athletevalue fetch --season 2026 |
Download inputs without fitting |
Seasons are keyed by ending year: 2026 is the 2025-26 season.
What each number means
| Output | Question | Method |
|---|---|---|
| Athletic impact | Points per 100 possessions a player adds over an average D1 player | Possession-weighted ridge regression (RAPM) on every lineup, shrunk toward a box-score prior fitted on earlier seasons |
| Wins above replacement | Wins the team gains versus a replacement-level player | Per-game win model over the team's actual schedule; three replacement definitions, one chosen |
| Program value | Revenue this season that the fitted model associates with those wins | School fixed-effects model of EADA revenue, plus a tournament-bid model and conference units |
| Roster market value | What a published tier budget would pay under a stated split | Allocation by role and rating (scenario); disclosed pay when the registry has it |
| Surplus | Program value minus price, annual on both sides | Difference of the two, on shared rating draws |
Every estimate carries an 80% interval and a status:
- ● reported: stated by a primary source.
- ◆ derived: computed from reported data by a fixed procedure.
- ▲ estimated: depends on a statistical fit or a published third-party figure.
- ○ scenario: depends on an assumption a user should question, such as which replacement level to use or how a conference splits tournament money.
A result takes the status of its weakest input. Because the replacement level is a choice, wins and every dollar figure are scenarios; the summary prints wins under all three definitions.
Validation
Each season fit is checked against the SportsDataverse league-wide RAPM, which is fit on the same possessions and shrinks toward zero (a reimplementation check), and against Bart Torvik's team ratings, which are not (an external check).
| Gate | 2025 | 2026 | Threshold |
|---|---|---|---|
| Spearman vs. reference RAPM, players with 500+ possessions, no-prior fit | 0.963 (2,817) | 0.975 (3,036) | ≥ 0.90 |
| Spearman of team net rating vs. Torvik AdjOE − AdjDE | 0.953 (321 teams) | 0.971 (324 teams) | ≥ 0.93 |
| Held-out error with box prior ÷ without, games held out, prior rebuilt per fold | 0.998 | 0.998 | ≤ 1.00 |
| Intercept, points per 100 | 103.9 | 106.0 | 95–112 |
| Home-court advantage per side, per 100 | 2.93 | 2.61 | 1–4 |
| Residual variance | 13,315 | 13,330 | 11,000–15,000 |
athletevalue validate --season 2026 reproduces this table. Torvik's site refuses
some cloud address ranges; when that happens the Torvik rows are skipped and reported.
The layers built on the ratings have no published reference, so
athletevalue validate --season 2026 --extended checks them against the data's own
outcomes:
| Gate | 2025 | 2026 | Threshold |
|---|---|---|---|
| Game-margin SD around fitted ratings, D1 games, points | 11.15 | 10.87 | 10–12.5 |
| Correlation of summed player WAR with team wins | 0.79 | 0.80 | ≥ 0.70 |
| Returning players: correlation gain from the prior | +0.122 | +0.124 | ≥ 0 |
| Share of revenue bootstrap draws with a win effect ≤ 0 | 0.00 | 0.00 | ≤ 0.10 |
| Largest gap between predicted and observed bid rate, by decile | 0.021 | 0.025 | ≤ 0.05 |
Every number in these tables comes from docs/_static/data/snapshot.json, built by
scripts/build_snapshot.py; a test fails if the README and the snapshot disagree.
What the box-score prior buys. Held-out squared error per 100 possessions, games held out, box totals and the team adjustment rebuilt from training games:
| Prior | 2025 | 2026 |
|---|---|---|
| None (λ = 1000) | 5,055.5 | 5,186.6 |
| Zero box information plus the team adjustment (λ = 3000) | 5,050.6 | 5,182.1 |
| Box model plus the team adjustment (λ = 3000) | 5,046.8 | 5,177.6 |
Most of the gain is the team adjustment restoring the scale of team strength; the box model itself adds about 0.1%. On 1,735 players who appear in both 2025 and 2026, the 2025 rating with the prior (trained on 2021–2024) correlates 0.52 with the 2026 no-prior rating, against 0.40 without it. The extended validation runs that check as a gate.
Data and licensing
| Source | Used for | Terms |
|---|---|---|
| SportsDataverse releases | Possessions, box scores, schedules, reference RAPM | Published from an MIT-licensed repository. The NCAA files are parsed from stats.ncaa.org by a producer repository with no license file, and the ESPN files from ESPN's public API; neither origin has granted rights and stats.ncaa.org's terms restrict automated access. MIT covers SportsDataverse's work, not those rights. |
| EADA | Men's basketball revenue by school, 2011–2025 | U.S. government work |
| Bart Torvik team results | Validation only | Season CSVs permitted by the site's robots.txt; not bundled, not used to fit |
| Press and methodology pages | Roster budgets, tournament unit value, conventions | Short quoted facts with URLs; see athletevalue assumptions |
Code is MIT. Curated data in src/athletevalue/data (the team crosswalk and the deal
registry) is CC BY 4.0; see LICENSE-DATA.
Data downloaded at runtime stays under its own terms and is never redistributed. A
commercial user should do their own diligence on the SportsDataverse chain.
KenPom and the Knight-Newhouse College Athletics Database restrict redistribution. The package has a reader for a user's own KenPom export, for local comparison, and an import-linter contract that stops fitting code from importing it.
Limitations
-
Program value measures an association. It does not estimate what one more win would cause. The win coefficient is identified from a school winning more or less than its own norm, and schools that spend more win more and earn more in the same years, so the coefficient can be biased upward. It counts only revenue schools attribute to men's basketball in EADA, which omits conference media money, donations and brand effects, a bias downward. The net direction is unknown. Sixty-one percent of school-seasons report revenue equal to expense and are excluded from the fit but kept in each school's revenue base, so for most programs the dollar figure is an elasticity from revenue-tracking schools applied to a budget number.
-
The replacement level is a choice. The NBA convention is −2.0 per 100. In these data the pooled low-minute players rate about −12, and the players ranked 9th–12th on each team about −1.2. The default uses the bench median; the summary shows all three.
-
Market value is an allocation for 2025-26 only. It spreads reported average roster budgets by role and rating and sums to the budget in every draw. Every conference outside the report's named top and middle tiers gets the bottom tier, including some programs whose real budgets are far higher.
-
Ratings are noisy and their intervals condition on the prior. A starter's net rating has a posterior SD near 2.6 points per 100 with the prior and near 4 without. The prior mean is treated as known. On synthetic seasons with known ratings, the 80% intervals without a prior cover 93% of true values: conservative, not overconfident.
-
Players are rated within a season. A
person_idlinks the same player across seasons for validation; ratings do not yet borrow strength from earlier seasons. -
Results agree to about 1e-15 relative between runs, because BLAS is multithreaded.
ATHLETEVALUE_DETERMINISTIC=1makes repeats on one machine bit-identical. Upstream files are pinned by SHA-256, so a re-cut release is detected rather than silently used.
METHODOLOGY.md gives the equations, fitted values and caveats for each layer. The documentation site renders it with the full validation report, every assumption with its source, and the API reference.
Roadmap
- 0.5.0: a bid model with strength of schedule, marginal tournament units and discounting; allocation dispersion and per-school budgets; a finer status taxonomy.
- Later: multi-season ratings with recency weights, in-season updates from CollegeBasketballData, then football.
Contributing
See CONTRIBUTING. The deal registry is not accepting rows until its correction and takedown process is in place; see PRIVACY.
Citation
If you use athletevalue in a publication, cite the software:
@software{hodge_athletevalue_2026,
author = {Hodge, John},
title = {athletevalue: open models of college basketball player impact,
program value and roster-market pay},
year = {2026},
version = {0.4.0},
url = {https://github.com/jman4162/athletevalue},
note = {Python package, MIT license; data files CC BY 4.0}
}
CITATION.cff carries the same metadata in a machine-readable form. Estimates are research outputs; read DISCLAIMER before using them for decisions.
Release files for athletevalue 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| athletevalue-0.4.0.tar.gz | 283.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| athletevalue-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 437.8 kB
Release files / athletevalue-0.4.0.tar.gz
| Download URL | athletevalue-0.4.0.tar.gz |
|---|---|
| Size | 283.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
17064770b89010ccb25f0a2d203d320cf11239311b64fb36402304777093f500
|
|
BLAKE2b-256 checksum How to use checksums |
9b185ac21b871706bdbec45392dea94013e0f6f07e13d1424ad6ec35748d7a01
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / athletevalue-0.4.0-py3-none-any.whl
| Download URL | athletevalue-0.4.0-py3-none-any.whl |
|---|---|
| Size | 154.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
cc54e96083d768498a9bfa860debd05f79a671d8095c68c4f0f6f9ce6f66dc4d
|
|
BLAKE2b-256 checksum How to use checksums |
c9176e513b80ef432a82ed1072dafbed14f3dd5bd06756b998eae1b4f6331fd0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|