Method and research
Beatn’ the Books compares a rating model with the betting market, then tests every idea on seasons it never saw. The short version: the NFL closing line is very hard to beat. One signal, wind, has held up so far.
2019–2025 · it can’t beat the closing line
average gap in win chance an hour before kickoff, 331 games
1. The market price
A moneyline becomes a probability with q = 1 / d, where d is decimal odds. Both sides add up to more than 100%; the extra is the book's margin. Removing it gives the fair price:
pfair = qhome / (qhome + qaway)Expected value always uses the price you'd actually get: Expected return (EV) = pmodel · d − 1, where d is the decimal odds. Break-even at −110 is 52.4%.
2. The Elo model
Every team has a rating, updated after each game since 1999 with a margin-of-victory multiplier. Each season pulls ratings halfway back to 1500. Settings were tuned on 2006–2015 only: K = 20, home field 55 Elo, rest 6 Elo per day (capped at ±35), and a 75-Elo penalty when a team starts someone other than its usual QB.
Phome = 1 / (1 + 10−Δ/400), Δ = Rhome + HFA + adj − RawayThe "Elo lean" blends the model with the market, 22% Elo and 78% market, and flags a side when that blend is worth betting (a positive expected return) at the posted price.
3. How Elo did against the closing line (2016–2025)
| Model | Accuracy score (lower is better) | Winners picked | Return, every edge | Return, edges over 3% |
|---|---|---|---|---|
| Elo, core only | 0.6353 | 63.6% | −6.3% | −8.3% |
| + rest + backup-QB flag | 0.6305 | 64.3% | −6.4% | −7.3% |
| Blend, 22% Elo (the "lean") | 0.6107 | 66.4% | −7.1% | −11.0% |
| Closing market | 0.6091 | 66.5% | benchmark |
Blindly betting every favorite lost 3.0%, every underdog 5.2%. Elo's picks did worse than no model. When it disagrees with the line, the market usually knows something it doesn't: injuries, QB quality, news.
This season so far
The same table for this season’s finished games, scored the same way at the final betting line. It updates after every game.
4. A better model: QB ratings and team efficiency
In October 2026 the model got two upgrades, tuned on 2006–2015 and tested once on 2016–2025:
- A rating for every quarterback, built week by week from his own games (yards, touchdowns, interceptions, sacks, rushing). A team’s strength now shifts with who is actually starting.
- Team efficiency (EPA), how well a team actually moves the ball and stops opponents, which is less luck-driven than final scores.
- Result: more accurate than before (and lost less at the final line: −5.5% instead of −6.4%), but still not as accurate as the closing betting line.
- A correction: a first check said lines moved toward the model’s picks 63% of the time during the week. That check accidentally knew each game’s starting QB before the line opened. Redone with only what’s known when lines open, it’s 56% (bet365) and 54% (Pinnacle), and the picks didn’t beat the opening price once the bookmaker’s margin is counted. See section 7.
- Injuries at every position were tested too (official reports 2013–2025, each player valued only by how much he plays). That version didn’t make the model more accurate on the test seasons, so it wasn’t used. The site also watches injury news live and alerts you when a key player is ruled out, in case Kalshi or Polymarket are slow to react.
October 6 upgrade: player value on an importance scale
- One league-wide quarterback scale. Before, a quarterback was only compared with his own team’s usual level, so a team that lost its star for a season (the Bengals without Burrow in 2025) kept a low rating after he came back. Now each team’s usual quarterback also counts against the league average. Tuned on 2006–2015, tested once on 2016–2025: more accurate in 8 of 10 seasons.
- Every other position on an importance scale. Each player on the final injury report counts by his position’s value × how much he plays: receivers and pass rushers 1.0, corners and offensive tackles 0.9, linebackers, safeties, tight ends and defensive tackles 0.6, guards and centers 0.5, running backs 0.4 (set in advance from published positional-value research). A full-time starter at a 1.0 position who is out costs his team 24 Elo, about 1 point on the spread; questionable players count half. A “skill” bonus from each receiver’s and back’s production was tested too and added nothing beyond playing time. Tuned on 2013–2018, tested once on 2019–2025.
- Result, on 2019–2025 (seasons it never saw): accuracy score 0.6319 → 0.6302, closing a small part of the gap to the closing line (0.6088). Its picks still lost at the final line, just less: every edge −9.0% → −7.0%, picks with a 5%+ edge −10.3% → −8.3% (moneyline) and −13.6% → −5.9% (spread). Winners picked slipped from 64.1% to 63.5%. A real but small improvement; it doesn’t beat the market.
5. Searching for an edge against the market
Instead of building a better standalone model, each idea was tested on top of the market's own price. If a signal adds nothing the market hasn't priced, its coefficient is zero.
logit P(outcome) = b0 + b1 · logit(pmarket) + b2 · signal- The rule was fixed in advance. A signal had to pass on 2001–2015 (|z| ≥ 2, same sign in both halves). Only then was 2016–2025 scored, once.
- 37 signals across moneylines, spreads and totals: rest, travel and time zones, divisional and home underdogs, last week's result, season against the spread, QB changes, referees, temperature, wind, and more.
- 8 injury signals were added later (2013–2025): snap share of players listed Out, Doubtful or Questionable, and starting QBs out. The market clearly moves on injury reports, but none passed the screen: by the close, injuries are fully priced.
- Moneyline and spread: nothing. Elo disagreement and the QB flag passed the screen, then lost to the closing line out of sample.
- Totals: wind. The totals model was the only one to beat the closing line out of sample, and wind did the work.
6. The wind signal
Bet the under when an outdoor game's forecast wind, averaged over the kickoff hour and the three hours after, is 10 mph or more. Retractable roofs don't count.
| Test | Wind source | Bets | Return |
|---|---|---|---|
| 2006–2015 (screening years) | Recorded at the game | 694 | +3.6% |
| 2016–2025 (out of sample) | Recorded at the game | 608 | +11.8% |
| 2022–2025 | Forecast shortly before kickoff | 168 | +14.2% |
| Late 2024–2025 | Forecast the day before | 105 | +7.2% |
| 2022 · 2023 · 2024 · 2025 | Forecast, by season | 52 · 33 · 41 · 42 | +26.8 · +39.2 · −25.7 · +17.8% |
Promising, not proven. About 40 bets a season, borderline statistical significance, a losing 2024, and 49 ideas tested to find it. Recorded wind isn't known before kickoff, which is why the forecast test matters. Stakes stay flat at 1% of bankroll, and the 10 mph threshold won't be tuned on these results. The Season page tracks it live.
7. Betting earlier in the week
A second historical dataset (opening and closing prices, 2014–2025) shows the market learns during the week. Can we get there first?
- Closing lines are sharper than openers, slightly at Pinnacle and clearly at the softer books (bet365, betr).
- Lines moved toward the model’s leans 54% of the time at Pinnacle and 56% at bet365, using only what’s known when lines open (each team’s previous starting QB). After the bookmaker’s margin, the leans were worth about the same as the final price (value −0.2% and −0.7%). betr’s 2025 openers did better (70%, +5.5%), but that’s one season and 96 bets.
- Predicting the move directly didn’t work. A model of where lines close (our model’s disagreement, favorites, last week against the spread, rest) explained under 1% of the movement in 2020–2025. Only rest passed the screen (lines drift toward the better-rested team), and it’s too small to bet.
- Windy-game totals drop more during the week (about −1.0 point vs −0.4 for calm games at bet365), and unders paid more at the open than at the close in every period. This uses recorded wind, which nobody has days ahead, so it overstates what a bettor could get.
8. Kalshi and Polymarket
Both exchanges publish their full price history, so the 2025 season and 2026 so far (347 games) could be tested at the prices you’d actually have paid, fees included.
| Test | Kalshi | Polymarket |
|---|---|---|
| Accuracy an hour before kickoff (sportsbooks’ final price: 0.6104, lower is better) | 0.6120 | 0.6118 |
| Model leans bought 6 days before: value vs the final price | −1.8% (150) | −0.5% (160) |
| Model leans bought 1 hour before: value vs the final price | −4.1% (143) | −3.3% (167) |
| Price gaps an hour before kickoff (2%+ better than the sportsbooks): actual return | +50% (15 bets) | +40% (24 bets) |
- The exchanges are almost as sharp as the sportsbooks. An hour before kickoff they were within 1 point of win chance of the sportsbooks’ final price on average.
- Buying the model’s leans early doesn’t pay. Lines moved a little toward them, but less than the fees and the bid-ask spread cost (about 3–4 cents on the dollar).
- Price gaps are rare and unproven. About one or two a week across both exchanges. They won, but on 39 bets that could easily be luck. The site keeps flagging them and the phone alerts keep firing so the record grows.
- The site now reads Kalshi and Polymarket prices directly from the exchanges on every update.
9. How each game’s bets are ranked
Every game card starts with its bets, best edge first, and the Best bets list uses the same order. Edge is the expected profit per $1 at the price you’d actually pay. A model’s own edge numbers can’t be trusted as-is, so each bet's chance of winning starts from the market’s fair price and is adjusted by what that kind of bet has really done:
| Bet | Edge comes from | Model’s own estimate | What it really returned |
|---|---|---|---|
| Wind under | How often windy unders beat the market, 2006 on | +2.2% | +11.8% |
| Model pick | How the model’s picks did in seasons it never saw, 2019 on | +7.3% | −7.1% |
| Price gap | The sportsbooks’ fair price (no long record yet) | — | 39 bets, too few |
- The table is at final prices (wind 2016–2025; model picks 2019–2025, the seasons today’s model never saw). The model’s biggest predicted edges did worst (top fifth −9.4%), so ranking by them tends to put the worst bet first.
- Checked on seasons they weren’t fitted on (previous model): the model-pick estimate (−5.0%) matched what happened (−6.3%, 2021–25). The wind estimate runs low (+2.7% vs +11.8%), which is the safe direction.
- Model picks on the moneyline and the spread are suggested when the model’s own edge is 5% or more (about six a week). They show that number in purple, next to how picks that strong have really done in 2019–2025: −8.3% on the moneyline (590 bets) and −5.9% on the spread (617 bets), plus this season’s record. They’re ranked by that record, not by the purple number: for a week (Oct 6–12, 2026) they were ranked by the model’s own edge, and in week 5 the top-ranked model picks (Dolphins, Cardinals, Browns) all lost, just as the backtest warned.
- Unit sizes: 1 unit (1u) = 2% of your Kalshi bankroll. Wind unders 1u (1.5u when the price makes the edge 6% or more; 0.5u when the roof must be open), price gaps 0.5u (0.75u when the model agrees), model picks 0.25u. Sizes follow the evidence, not the edge alone: our edge estimates aren’t reliable enough to bet more just because a number is bigger.
- Other bets with an edge of zero or less are listed under “not worth it at this price”. A game with none says pass. Each bet also shows how strong its evidence is: wind is tested, price gaps are unproven, model picks have no proven edge.
10. Data and updates
- Games, scores, lines and projected starters: nflverse games.csv. Lines usually appear a day or two before kickoff.
- Wind: Open-Meteo forecasts for each stadium, refreshed on every update and frozen at kickoff.
- Kalshi and Polymarket: moneyline prices straight from each exchange’s public feed (what you’d pay, before fees), refreshed on every update.
- Sportsbook prices (on the private version): The Odds API. For upcoming games the market number is the median no-vig price across books; without it, the nflverse betting line. Finished games are always scored at the nflverse closing line, the same way the backtests were.
- The site rebuilds from fresh data several times a day. Every number on it is computed by the same Python code that ran the backtests.