Data Matrix — Three Pillars Audit

What we hold · what's missing · what it costs to get
Headline: of ~38 components across the three pillars, we hold 19, partially hold 7, and lack 12. But 3 substantial datasets are already on disk and never used — those come first, because they're free.

Pillar 1 · Core Form

ComponentStatusWhereTo get it
Finishing position per runHAVE nsw_all.pos—
Days since last runHAVE derived from date—
1st/2nd/3rd up (spells)HAVE derived⚠ cross-state error, bounded
Career record (wins/places)HAVE derived per horse—
Record at distanceHAVE distance_m (fixed today)—
Record at trackHAVE derived—
Track × distance recordHAVE derived—
Class / race gradeHAVE race_class—
Prize money of raceHAVE prize—
Career earningsPARTIAL career_prize 55% · career_avg 51%—
Winning time / marginsHAVE win_time_s · margin—
In-running positionsPARTIAL at400m · at800m ⚠ look-ahead — same race
Last-5 form stringMISSING null at sourcenot available
Sectional splitsPARTIAL + UNUSED sectionals_full.csvATC only, ~887 rows
Stewards' narrativesMISSING ~200 PDFs unparsedPDF extraction

Pillar 2 · Physical Attributes

ComponentStatusWhereTo get it
Age · sex · colourHAVE nsw_all—
Weight carriedHAVE weight—
Barrier / drawHAVE barrier—
Handicap rating + movementHAVE hr 64% · rating_prog—
Sire + dam namesHAVE sire · dam — 100%—
Progeny performanceMISSING — sire record · dam's produce · siblings
Gear / blinkers / tongue tieMISSING null at sourcenot available
Track condition / goingMISSING null in nsw_all ✅ PuntersEdge going_rating
Wet-track aptitudeMISSING needs going + years of historyblocks on going
Track penetrometerMISSING —Krok runner-form
Rail positionMISSING —✅ PuntersEdge next-to-go
Weather / rainfallMISSING —Krok /v1/weather

Pillar 3 · Market Dynamics

ComponentStatusWhereTo get it
Open / close price per runnerPARTIAL tips_all 20% · cl_all 100%—
Per-bookmaker fluc pathsHELD · UNUSED tips_json ▸ flucsWinalready on disk
Tipster counts per horseHELD · UNUSED tips_json ▸ RaceTippersalready on disk
Book coverage per raceHAVE 14–18 books—
Cross-book spreadHAVE up to 30%—
Deductions / scratchingsHAVE res_ded · 7.46c mean—
Overround by time-to-jumpHAVE 1.202 → 1.126—
Tote exotic dividendsPARTIAL res_exotic 290 races—
Betfair BSPMISSING —Krok /v1/exchange?source=bsp
Market moversMISSING —Krok /v1/racing/movers
Exchange liquidity / matched volumeMISSING —Krok runner-form (confidence)
Steam / drift velocityHELD · UNUSED flucs arrays in 2,700 filesalready on disk

Recommended sequencing

1 · Mine what's on disk — free, no new source
  • flucsWin per bookmaker → timing/steam angles on 2,000+ races
  • Tipster counts → the follow-the-crowd question
  • sectionals_full.csv → pace and closing-speed angles
2 · Validate the candidate — the priority
  • Fetch the 9,262 non-NSW races (~70 min)
  • Run the five-condition score unchanged
  • Win-rate gradient first, then ROI with tips
  • Different state = different population = real test
3 · Fill the two cheap gaps
  • going_rating from PuntersEdge — already paid for
  • Rail position + track condition from next-to-go
  • Unlocks wet-track angles, including your greys-in-the-wet example
4 · Only then, new sources
  • Progeny data — needs a real source, not scraped
  • Krok BSP, movers, exchange liquidity — 50 req/mo ceiling
  • Stewards' PDFs — extraction pipeline, ~200 files
The risk to name: gathering is not evidence. Widening the matrix from 19 to 38 components does not raise the probability that the score works — it raises the number of things we could overfit to. And every component added to a search is another chance to find a false positive.

The one asymmetry in our favour: a component that's genuinely absent from the market is worth having. Going, rail and penetrometer are the best candidates — they're track-level, they change the going, and a general pricing model handles them coarsely.
19 held · 7 partial · 12 missing · 3 held-and-unused