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.
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) × 100Worked 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.
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.
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%.
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.
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 streakThe 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.
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.
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.
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.