Closing-line value is not whether a bet wins. It is whether the price you took was better than the final price available before kickoff. That distinction matters today because our Week 1 board has moved, while our NFL live_pregame graded ledger has no eligible rows yet.
So the first CLV Ledger starts with two ledgers, not one. The market ledger can show what our own captured prices have done. The graded ledger cannot show live CLV until eligible picks settle and carry a recorded closing benchmark. That second ledger starts empty on purpose.
What moved on our board
For a clean apples-to-apples board, we use Bovada because our capture covers every Week 1 game on the same book. “Captured open” means the first Bovada spread we stored for that game, not the market’s true opener. “Current” means the latest stored Bovada spread asOf 2026-08-31T15:45:00Z. Six of 16 games have moved between those two observations asOf 2026-08-31T15:45:00Z; 10 have not.
| Game | Captured open | Current |
|---|---|---|
| BUF at HOU | HOU -1 asOf 2026-08-22T14:11:47.979Z | PK asOf 2026-08-31T15:45:00Z |
| BAL at IND | BAL -3 asOf 2026-08-22T14:11:47.979Z | BAL -3.5 asOf 2026-08-31T15:45:00Z |
| CLE at JAX | JAX -7.5 asOf 2026-08-22T14:11:47.979Z | JAX -8 asOf 2026-08-31T15:45:00Z |
| MIA at LV | LV -4 asOf 2026-08-22T14:11:47.979Z | LV -3.5 asOf 2026-08-31T15:45:00Z |
| NYJ at TEN | TEN -2.5 asOf 2026-08-22T14:11:47.979Z | TEN -2 asOf 2026-08-31T15:45:00Z |
| TB at CIN | CIN -3.5 asOf 2026-08-22T14:11:47.979Z | CIN -4 asOf 2026-08-31T15:45:00Z |
| ARI at LAC | LAC -10 asOf 2026-08-22T14:11:47.979Z | LAC -10 asOf 2026-08-31T15:45:00Z |
| ATL at PIT | PIT -3 asOf 2026-08-22T14:11:47.979Z | PIT -3 asOf 2026-08-31T15:45:00Z |
| CHI at CAR | CHI -2.5 asOf 2026-08-22T14:11:47.979Z | CHI -2.5 asOf 2026-08-31T15:45:00Z |
| DAL at NYG | DAL -3 asOf 2026-08-26T16:15:00Z | DAL -3 asOf 2026-08-31T15:45:00Z |
| DEN at KC | KC -2.5 asOf 2026-08-26T16:15:00Z | KC -2.5 asOf 2026-08-31T15:45:00Z |
| GB at MIN | MIN -1.5 asOf 2026-08-22T14:11:47.979Z | MIN -1.5 asOf 2026-08-31T15:45:00Z |
| NE at SEA | SEA -3.5 asOf 2026-08-26T16:15:00Z | SEA -3.5 asOf 2026-08-31T15:45:00Z |
| NO at DET | DET -7 asOf 2026-08-22T14:11:47.979Z | DET -7 asOf 2026-08-31T15:45:00Z |
| SF at LA | LA -3.5 asOf 2026-08-26T16:15:00Z | LA -3.5 asOf 2026-08-31T15:45:00Z |
| WAS at PHI | PHI -4.5 asOf 2026-08-22T14:11:47.979Z | PHI -4.5 asOf 2026-08-31T15:45:00Z |
The move is not the CLV
The loudest move is BUF at HOU: Houston went from -1 asOf 2026-08-22T14:11:47.979Z to pick’em asOf 2026-08-31T15:45:00Z. Five other games moved by a half-point over their captured windows asOf 2026-08-31T15:45:00Z. That tells us where the board traveled. It does not tell us who beat the close.
To grade CLV, we need the exact side and line recorded when a pick became live, then the closing line from the same market. A move can help one side and hurt the other. Baltimore -3 asOf 2026-08-22T14:11:47.979Z is half a point better for a Baltimore backer than Baltimore -3.5 asOf 2026-08-31T15:45:00Z. But the latter is still a current capture, not a graded CLV row. The eligible settled record decides what enters this ledger.
The historical answer is also empty — for the right reason
We checked the graded spread backfill under the only provenance allow-list this ledger accepts: live_pregame. AsOf 2026-08-31T16:00:21.225367Z, that NFL-only query returns no graded win/loss/push spread rows and no populated CLV rows. That means we do not have a provenance-eligible historical ATS record to claim for “moves that beat the close.” We will not substitute leaked backfill, and we will not turn a batch stamp into a fake timeline: graded_at is a grading batch stamp, not the time axis for this franchise.
The Week 1 schedule tells the same story from the front. There are 16 scheduled games and no finals asOf 2026-08-31T15:55:05.840388Z; the scheduled window runs from 2026-09-09 through 2026-09-14 asOf that same query. No live graded CLV exists yet because there is nothing live to grade.
The ledger starts at zero
That is the point of publishing it now. We could wait until the first good-looking streak and launch a “track record” with a flattering denominator. Instead the record begins before the outcomes exist. Every week, the market ledger can show what moved. Once games close and eligible picks settle, the graded ledger can add ATS record and CLV from the same allow-listed provenance. Until then, the honest row is empty.
The only promise of this franchise is that zero stays zero until the tables say otherwise.
VERIFY
Run these read-only queries against production. Q1 produces every spread and movement count shown above; Q2 proves the graded CLV empty state; Q3 proves the Week 1 final-game empty state. For Q1, each captured_at value is the asOf for its price; Q2 and Q3 use their query timestamp as the asOf. Q2 deliberately does not use graded_at as a window.
-- Q1: odds_snapshots + nfl_schedules, Bovada captured open versus current
with week1 as (
select game_id, away_team, home_team
from public.nfl_schedules
where season=2026 and week=1 and game_type='REG'
), ranked as (
select w.away_team, w.home_team, o.game_id, o.id, o.captured_at, o.spread_home,
row_number() over (partition by o.game_id order by o.captured_at asc, o.id asc) as rn_open,
row_number() over (partition by o.game_id order by o.captured_at desc, o.id desc) as rn_current
from public.odds_snapshots o
join week1 w using (game_id)
where o.book='bovada'
), paired as (
select game_id, max(away_team) as away_team, max(home_team) as home_team,
max(captured_at) filter (where rn_open=1) as open_as_of,
max(spread_home) filter (where rn_open=1) as open_home_spread,
max(captured_at) filter (where rn_current=1) as current_as_of,
max(spread_home) filter (where rn_current=1) as current_home_spread
from ranked
group by game_id
)
select away_team, home_team, open_as_of, open_home_spread, current_as_of, current_home_spread,
current_home_spread - open_home_spread as home_spread_move,
count(*) over () as games_covered,
count(*) filter (where current_home_spread != open_home_spread) over () as games_moved,
count(*) filter (where current_home_spread = open_home_spread) over () as games_unchanged
from paired
order by abs(current_home_spread - open_home_spread) desc, away_team, home_team;
-- Q2: provenance-eligible graded spread ledger
select
now() as as_of_utc,
count(*) filter (where pr.bet_outcome in ('win','loss','push')) as graded_ats_rows,
count(*) filter (where pr.clv is not null or pr.clv_cents is not null) as rows_with_clv,
count(*) filter (where pr.bet_outcome='win') as wins,
count(*) filter (where pr.bet_outcome='loss') as losses,
count(*) filter (where pr.bet_outcome='push') as pushes
from public.prediction_results pr
join public.predictions p on p.id = pr.prediction_id
where pr.sport_key='nfl'
and pr.prediction_type='game_spread'
and pr.provenance_tier='live_pregame'
and p.provenance_tier='live_pregame';
-- Q3: Week 1 schedule state
select
now() as as_of_utc,
min(gameday) as first_gameday,
max(gameday) as last_gameday,
count(*) as week1_games,
count(*) filter (where is_final) as final_games
from public.nfl_schedules
where season=2026 and week=1 and game_type='REG';
This is analytics, not advice — bet responsibly, set your own limits, and never chase losses.
Model calibration from graded predictions
Calibration points render only when a verified source binds prediction probabilities to settled outcomes for the same observations.
Expected value from graded outcomes
Expected-value cells render only when a verified source binds observed win outcomes to the price paid for the same bets.





