Modelled closing line for tracked bets
Date: 2026-08-31. Status: design approved in principle; model choices and caps are set by the backtest inv3/cmd/closebacktest.
Problem
A Terminal-tracked bet gets its CLV from the reference book’s closing price for the exact line it was tracked at. When that line is not on the book’s closing board the bet has no CLV. After the exact-close fixes (oddsapi #442, hub #1028) the remaining misses are lines the book no longer quoted at close: the main line moved (basketball median move 4 pts against a stored window of 2.5 pts), single-line markets (NFL, team totals, tennis totals, most player props), or a market with no capture for that book. Goal: every tracked bet gets a CLV, with an honest label and a measured error.What the capture gives us
historical.closing_odds holds, per book and market, a WINDOW of lines around
the closing main line (basketball 11 rungs, football 7, halves/corners 5,
NFL / team totals / tennis totals / most props 1), each with both sides priced.
The 1X2 / ML is captured too. There is no full board.
Model
Every lined market is a bet on an integer latent quantity X: total points or goals (totals), or home margin (spreads, threshold -line). A rung of the ladder is then (threshold t, fair price for “X above t”, fair price for “X below t”), the fair prices from the shared LOG de-vig (utils.NoVigFromRow).
Fair price of a line under a distribution D over the integers, with pushes and
quarter lines handled exactly: split the line into its components (a quarter
line is two half stakes on the adjacent half and whole lines), then
fair = 1 + sum(P(lose)) / sum(P(win)) over the components. This is the
identity bettors use, not an approximation.
Two distribution families, chosen per sport by the backtest:
- Normal with continuity correction (mean, sd): basketball, American football, tennis games, handball, volleyball, esports maps, yards-type props.
- Poisson family: Poisson(lambda) for goal/run/corner/card totals and count props; Skellam for goal-margin spreads, with the goal total taken from the event’s own totals ladder when present, else a sport prior.
Tiers and labels
exact: quoted line at the reference book (existing).derived: identities on quoted markets (DNB / Double Chance from 1X2; quarter line from its two halves when both are quoted). Exact.modeled: the fitted distribution evaluated at the bet’s line. Stored with the anchor (closing main line and its fair price), the distance from the nearest quoted rung, and the family used. Shown as “est.” in the tracker, with the hover text naming the main line it was priced from. Excluded fromodds-verifiedon public records; filterable in stats.- Refused: no reference market rows for the event, or distance beyond the per-sport cap set from the backtest.
Where it lives
Go only, inv3/closemodel, called from resolveSettlementOutcome after the
exact and derived attempts fail. The hub stores closingSource and the anchor
fields and renders them; it does not reimplement the model (live CLV for open
bets keeps refusing until an endpoint exposes the model).
Backtest (this is what makes “accurate” a measured claim)
v3/cmd/closebacktest reads recent Pinnacle (and DraftKings prop) ladders from
historical.closing_odds (read replica, read-only) and reports the CLV error
of a predicted rung against its real de-vigged price:
- Interpolation: leave one interior rung out.
- Extrapolation: hold out the top 1..3 rungs of the window, predict from the rest. This is the real “line moved past the window” case.
- Single anchor: fit on the main rung only with the prior dispersion, predict every other rung. This is the NFL / team total / prop case.