Undrafted

A valuation model for sports cards that surfaces undervalued players before the market catches up.

Role

Design Engineering

Product

Data analytics

** This is an ongoing project. This page will be updated as it progresses.

** This is an ongoing project. This page will be updated as it progresses.

** This is an ongoing project. This page will be updated as it progresses.

The problem

Basketball card collecting has a timing problem. The players worth buying are obvious in hindsight — after the breakout season, after the All-Star selection, after the national coverage. By then the price has already moved. The collectors who got in early weren't necessarily smarter; they just had a better read on where the player was headed before the market did.

The market prices cards on narrative. Stats and performance take longer to show up in what people are willing to pay, and that lag is the opportunity. The question was whether that gap was measurable — and whether catching it early was a repeatable process, not just luck.

My role and constraints

I did everything solo: framing the problem, designing the scoring model, building the prototypes, and wiring up the data layer. The constraint that shaped everything: no reliable real-time price data without an API, and no API without going and getting one. That meant designing the model architecture first, with mock data standing in, so the system was ready to accept live data the moment the pipeline existed.

The output is still being decided. This started as a potential mobile app, but the more the model developed, the clearer it became: the algorithm is the product. The interface is there to test the model, not the other way around.

Process

  1. Defined the signal. Before anything was built, I worked out what "undervalued" actually means here: a player whose statistical trajectory is outpacing what collectors are paying. That gap — and specifically its percentage, not its raw size — is the core signal.

  2. Built the scoring model. Two scores per player: Stat IQ (performance-based, rising with on-court improvement) and Card IQ (market-based, derived from sale price trends). The gap between them, expressed as a percentage, is the valuation signal.

  3. Designed the signal states. Rather than a binary buy/sell, I built a five-state compression engine: ASLEEP (gap open, market flat), WAKING (Card IQ just starting to move after a flat period — earliest detectable confirmation), CLOSING (gap actively shrinking), CLOSED (market caught up), PEAKED (card overshot, gap negative). WAKING is the target entry state.

  4. Prototyped and tested the model. Built an interactive backtest dashboard to check whether the signal fired at the right time historically. Caught a key flaw — v0.1 fired BUY exactly when prices started declining — and corrected it: BUY now requires Stat IQ + Card IQ lag only, with no narrative signal required. Narrative arriving is a sell signal, not a buy signal.

  5. Built the data infrastructure. Separated the data layer entirely from the chart rendering: PRICE_DATA, GAP_DATA, and EVENTS are pure data objects. The eBay API integration slots in by replacing those arrays — no chart code changes.

Key decisions

  1. Percentage gap, not raw points. A 10-point gap between Stat IQ and Card IQ means something very different at Card IQ 85 (11.8% undervalued — significant) than at Card IQ 110 (9.1% — much less so). Normalizing by percentage makes the signal consistent across players at different price levels.

  2. BUY fires before the narrative, not after. The original model required all three signals: rising stats, lagging card price, and narrative (media coverage, social buzz). Testing showed this fired too late — narrative is a confirmation of what the market already knows, not a leading indicator. The corrected model fires BUY on stats + price gap alone. When narrative arrives, that's the exit signal.

  3. WAKING as the primary target state. Card IQ moving 1–2 points after three or more months flat, while the gap is still open at 6%+, is the earliest detectable moment the market has noticed. Price hasn't moved yet. Designing the model around that specific state — not just "gap is open" — is what makes it actionable rather than descriptive.

  4. The output format is still open. The honest version: this could ship as a mobile app, a web tool, a paid data product, or something else. The model works. The right delivery mechanism is a question for validation with real users, not a design assumption baked in early.

Outcome

The signal model works against reconstructed historical data, and the architecture is ready for live eBay price feeds. What I can point to now: a valuation framework with a defensible logic, interactive prototypes that test it, a backtest that caught and corrected a real flaw in v0.1, and a data pipeline designed to accept real-world data cleanly.

What I'll validate next: whether the WAKING signal fires early enough in practice to be actionable — and whether the gap% threshold (currently 6%) is the right floor, or needs tuning per player tier.