01The problem
Off-the-shelf rankings and public draft data answer the wrong question for an auction. They give you the consensus order — not what a player is worth at your league's exact settings, and not where the market is systematically wrong. So the design stance was simple, and it's the spine of the whole thing: price what a player is worth, not what he'll cost. The gap between those two numbers is the only place an edge can come from — so the model refuses to forecast the market and instead tries to be unarguably right about value. That way, every time the market disagrees with it, the disagreement is a signal.
02What I built
The engine is a staged pipeline. It starts from what a player actually earned, strips the luck out of it, applies bounded adjustments for what genuinely changed — age, role, team, situation — and describes the resulting range. Then, for price, it converts that range into dollars for one specific league's rules.
One score, two products: settings-light rankings that travel between leagues, and settings-heavy prices that don't. They're allowed to disagree by design.
Every tunable number lives on a settings tab, never buried inside a formula — which is what made 40+ iterations tractable. Two hard-won rules hold it together: a role adjustment picks which baseline a thin-sample player regresses toward — it never multiplies his own history (do that and you project a third-string QB at 51 points a game) — and availability is priced exactly once, because charging it to both the ranking and the price double-counts a backup.
03The data
Everything runs on free, public data — open-source play-by-play, rosters and depth charts plus public draft data — with no paid feeds or API keys. The real work was in the joins: there's no shared player ID across the sources, so matching is done on normalized name and position, with measured, documented match rates (~88% / ~82% / ~44%, the last one low only because the market simply doesn't track deep-bench players). A mid-stream schema change and a 490,000-row rolling depth-chart file each had to be handled explicitly, and a scoped refresh script re-pulls only the volatile fields near draft day while never touching completed seasons. The one place the pipeline is blind — a player who becomes relevant after build time — is flagged in the open, not hidden. Knowing exactly where a system can't see is part of trusting the parts that work.
04Validation — the honest version
The most important number is one a less disciplined project would bury: as a pure ranker, the model loses to the public market (rank correlation 0.484 vs 0.567). But the ranking was never the product — the edge is. Where the model diverges from consensus, those disagreements predict outperformance: players it rated above the market beat their draft slot by 6.4 spots on average at receiver. It was validated out-of-sample across 14 seasons, and the league's exact scoring was reverse-engineered from data (171 of 200 players reconstructed to the point), which caught a rule quietly costing ~10 points a player.
The part that most resembles real analytical work is what got thrown out:
"He finished the season strong" — killed. Strong finishers actually regress harder; last-five-games form is a worse predictor than the full season.
A second-year-coordinator bump — killed. It was just regression to the mean; any below-average offense gains about the same the next year.
A coaching "feeds his WR1" narrative — killed. The effect tracked one elite player, not the scheme, and vanished when he declined.
The rule that came out of it, now standing: never report a group difference without the control that might explain it away. That instinct — asking what the base rate is before getting excited — is the difference between a model and a pile of gut feels.
05From value to a decision
Pricing a player is only half the job; the other half is how to actually spend the budget. I re-priced the prior year's entire auction in hindsight to learn what the room really pays for, then ran a Monte-Carlo of 20,000 simulated seasons across 773 candidate budget shapes. What survived its own controls: draft surplus correlates +0.86 with final standings — the strongest result in the project; the most expensive tier is the only losing tier (you pay a premium for certainty you already had cheaper); and spreading the money beats spiking it. That became three budget postures and a live target board — the bridge from "the model says" to "raise your hand for this player," usable under real draft-day pressure.
06Results
I used it to draft two live auctions in 2026. In the ten-team league it was built for, it drafted +$131 of surplus value — first of ten teams, next-best +$34 — and owned the three highest-surplus picks in the room. In a second, independent twelve-team league, the same engine re-tuned to that format finished first of twelve, at +$42.
Stated the way the project states it: the surplus number is the model grading its own board, so it's proof of an efficiently-drafted board, not a guaranteed championship. What makes it credible is that the same market-behavior patterns held across two seasons and two leagues — the room reliably overpays the top of one position and underprices another — and the model found those patterns before the drafts, not after.
07Why it's here
Strip away the football and what's left is a complete analytics workflow, shipped end-to-end by one person with AI as the build partner across 40+ versioned iterations: public-data ETL with real schema drift, a backtested statistical model, honest out-of-sample validation, and a decision tool used live. The thing I'm proudest of isn't the wins — it's that the model documents its own weak points (a compressed price at one position, a known-broken edge column) as loudly as its strengths. Knowing exactly where a model is blind is what makes the rest of it trustworthy. That's the same instinct I bring to product and operations: build the thing that changes the decision, be honest about what it can't do, and ship it.