Methodology

How every number here is calculated.

Analytics you can't audit are just vibes with decimals. This page gives the actual formulas, the actual constants, and — for each method — what it genuinely cannot tell you. If a figure anywhere on TrueLine looks wrong, this is the page to check it against.

The core measurement

Closing line value

Source: supabase/functions/_shared/clv.ts · api/cron/backfill-clv

CLV is computed in implied-probability space, not odds space. American odds convert to an implied probability first, because odds themselves don't average or difference linearly — treating them as if they do is the most common way betting analytics goes quietly wrong.

implied(a) = a > 0  ?  100 / (a + 100)
                    :  |a| / (|a| + 100)

CLV% = (implied(close) − implied(entry)) / implied(entry) × 100

Worked example, computed on this page by the same function that grades your bets — you bet +150 and it closes at +130:

implied(+150)  = 40.00%
implied(+130)  = 43.48%

CLV% = (43.4783 − 40.0000) / 40.0000 × 100
     = +8.70%

Positive means you got a better price than the market settled at. The benchmark is Pinnacle's close, and only Pinnacle's. When Pinnacle never priced an event, the bet is left ungraded with a recorded reason — we don't substitute another book's close, because a CLV figure whose benchmark changes per bet isn't a measurement, it's a mood.

What this cannot tell you

CLV is evidence of edge, not proof of profit, and it is noisy over small samples. A handful of bets with good CLV tells you almost nothing; a few hundred starts to mean something. It also can't see closing lines that were never captured — bets on events outside our archive window simply aren't graded.

Skill vs variance

Betting Sharpe ratio

Source: src/lib/analytics/engine.ts · calculateVolatility()

Raw ROI can't distinguish a steady grinder from someone who hit one 12-leg parlay. The Sharpe ratio divides your average return by how much that return bounces around, so consistency counts.

rᵢ         = profit(betᵢ) / stake(betᵢ)      per-bet return
mean       = Σ rᵢ / n
variance   = Σ (rᵢ − mean)² / (n − 1)       sample variance
volatility = √variance

Sharpe     = mean / volatility

The quality bands shown in-app are:

Sharpe > 0.30   excellent
Sharpe > 0.15   good
Sharpe > 0.05   mediocre
Sharpe > 0      poor
Sharpe ≤ 0      negative

Only settled won/lost bets count — pushes are excluded rather than scored as zero returns, since a push isn't an outcome your edge produced. Below three settled bets the figure isn't computed at all.

What this cannot tell you

This is a per-bet Sharpe with no risk-free rate and no annualisation, so it is not comparable to a hedge fund's Sharpe ratio — the same label, a different quantity. The bands above are our own convention, not an industry standard. And it assumes your bets are independent, which they aren't if you routinely bet correlated sides of the same game.

Survival

Risk of ruin

Source: supabase/functions/analytics-risk-of-ruin

Risk of ruin answers one question: given your edge and how much you stake, what is the probability your bankroll reaches zero? It is computed two ways.

Analytical (everyone, including the free tier)

p       = win rate, clamped to [0.01, 0.99]
q       = 1 − p
b       = decimal odds − 1               net payout per unit
cushion = 100 / max(0.5, stake%)         units of bankroll

if p·b ≤ q:   ruin = 1.0                 no edge → ruin is eventually certain
else:         ruin = min(1, (q / (p·b)) ^ cushion)

Simulated (Pro and above)

A Monte Carlo pass runs 1,000 bankrolls of 500 bets by default, staking a fixed percentage each time and counting how many fall below 1% of their starting balance. The reported figure is simply that bust count over the run count. Risk levels are banded at 2%, 10% and 25%, and the recommended maximum stake is the largest whole percentage that keeps analytical ruin under 5%, capped at 10%.

What this cannot tell you

Both methods assume a fixed edge and a fixed stake percentage forever, which no real bettor has — your true win rate is itself an estimate from a finite sample. The analytical form is a standard approximation, not an exact solution, and treats the bankroll as a whole number of units. Read it as a comparison tool between staking plans, not a prophecy about your account.

The next 90 days

Monte Carlo bankroll simulation

Source: supabase/functions/analytics-bankroll-simulation

The Bankroll Digital Twin projects forward by replaying your betting profile thousands of times. It runs 1,000 independent paths by default over the horizon you choose, and reports the distribution rather than a single headline number.

per day, per path:   simulate bets from your profile
                     (win rate, odds, staking / Kelly fraction)

outputs:
  percentile bands   p10 · p25 · p50 · p75 · p90   per day
  median final bankroll, plus p10 and p90 finals
  probability of ruin across all paths
  average maximum drawdown
  average longest losing streak

The percentile fan is the point. A median outcome on its own hides the fact that the 10th-percentile path — one bettor in ten, with identical skill — can look like a disaster over the same window. Variance is not a rounding error at these sample sizes.

What this cannot tell you

Every path is drawn from the profile you give it, so the output is only as good as that input — garbage edge in, confident garbage out. It assumes independent bets and a stationary edge, models no correlation between wagers, and cannot know that the market will adapt to you. 1,000 paths is enough to shape the distribution, not enough to pin down extreme tails precisely.

Provenance

Where the data comes from

Source: vercel.json · api/cron/snapshot-odds

Odds are captured from the sportsbooks we track every 30 minutes, around the clock, since March 2026. That is the whole archive — we don't imply years of history we don't have. Closing lines are stored per event so that CLV is graded against a real captured price rather than reconstructed after the fact.

The same archive powers the public CLV archive and the MLB closing-line study. Both are published so the methodology above can be checked against real output rather than taken on trust.

What this cannot tell you

A 30-minute cadence means we see the shape of a line's movement, not every tick. Sharp moves that open and close inside a single interval can be missed, and a book that was briefly off-market between captures won't appear in the archive at all.