Skip to main content

Overview

Every value bet in /api/value-bets passes through 5 mathematical layers before reaching you. This page explains each one in plain language, with formulas and worked examples. The fields returned by the API map directly to these layers:
API fieldWhat it represents
pinnacle_oddsRaw Pinnacle quoted price
fair_oddsPinnacle devigged (margin removed)
ev_pctEdge over fair value (bookmaker_odds / fair_odds - 1)
payout_rateDisplay quality gate (raw opposite Pinnacle odds substituted in)

Step 1 — Implied probability

Every decimal odds price implies a win probability:
implied_probability = 1 / decimal_odds
Examples:
  • 2.001 / 2.00 = 0.500 (50%)
  • 3.501 / 3.50 = 0.286 (28.6%)
  • 1.701 / 1.70 = 0.588 (58.8%)
If you sum implied probabilities across all outcomes in a market, the total is always above 100% — the excess is the bookmaker’s margin.

Step 2 — Raw Pinnacle TRJ (devig input only)

For a market with N outcomes, Raw TRJ is the sum of all implied probabilities:
Raw TRJ = Σ (1 / pinnacle_odds_i)

# 2-way example: spread or total
TRJ = 1/2.05 + 1/1.88 = 0.488 + 0.532 = 1.020  → 2.0% margin

# 3-way example: football moneyline
TRJ = 1/2.05 + 1/3.40 + 1/3.50 = 0.488 + 0.294 + 0.286 = 1.068  → 6.8% margin
Pinnacle’s natural TRJ ranges:
  • 2-way markets (spread, total, tennis): ~1.02–1.05
  • 3-way markets (football 1X2): ~1.05–1.10
Raw TRJ is a devig input — it feeds into the fair-odds formula below. It is not the quality gate shown as payout_rate in the API. See Step 5 for the distinction.

Step 3 — Fair odds (devigging)

Devigging removes Pinnacle’s margin to produce the true consensus probability for each outcome. Formula for 2-way markets (spread, total, tennis moneyline, BTTS):
fair_odds = (2 × pinnacle_odds) / (2 − pinnacle_odds × (1/TRJ − 1))
Formula for 3-way markets (football moneyline, European handicap):
fair_odds = (3 × pinnacle_odds) / (3 − pinnacle_odds × (1/TRJ − 1))

Worked example — 2-way total

Pinnacle: Over 2.5 @ 1.92 | Under 2.5 @ 1.98

TRJ = 1/1.92 + 1/1.98 = 0.521 + 0.505 = 1.026

fair_odds(Over) = (2 × 1.92) / (2 − 1.92 × (1/1.026 − 1))
               = 3.84 / (2 − 1.92 × 0.0253)
               = 3.84 / 1.9514
               = 1.967   ← true market price for Over 2.5

Worked example — 3-way football

Pinnacle: Home 2.05 | Draw 3.40 | Away 3.50

TRJ = 1/2.05 + 1/3.40 + 1/3.50 = 0.488 + 0.294 + 0.286 = 1.068

fair_odds(Home) = (3 × 2.05) / (3 − 2.05 × (1/1.068 − 1))
               = 6.15 / (3 − 2.05 × (−0.0637))
               = 6.15 / 3.131
               = 1.964
The fair odds represent the bet’s true consensus price — what Pinnacle would offer if they had zero margin.

Step 4 — Fair odds floor (safety buffer)

Before EV is computed, a small safety buffer is applied to the fair odds to prevent noise:
fair_odds_final = fair_odds × 1.01           # all markets (+1% buffer)
fair_odds_final = fair_odds × 1.01 × 1.03   # player props (+4.04% total)
Why this exists: Tiny Pinnacle pricing fluctuations can create apparent EV at the margin. The floor ensures only bets with a genuine edge clear the minimum. Effect: For standard markets (spread, total, moneyline), a bookmaker needs roughly +2% raw edge over devigged Pinnacle to show ev_pct ≥ 1%. For player props, it’s roughly +5% raw edge. This explains why many bets that look close don’t appear in the feed.

Step 5 — EV% calculation

Once fair odds are established (with floor applied):
EV% = (bookmaker_odds / fair_odds_final − 1) × 100

Worked example

Pinnacle: PSG @ 1.90 (fair odds after devig + floor = 1.929)
Betsson offers PSG @ 2.05

EV% = (2.05 / 1.929 − 1) × 100 = +6.27%
What ev_pct means in plain English:
A +5.0% EV bet means that if you placed this exact bet repeatedly under the same conditions, you’d expect to profit an average of 5per5 per 100 wagered over the long run.
Short-term variance is high — a single bet can win or lose. EV only plays out over large sample sizes. The edge comes from the bookmaker mispricing one outcome relative to Pinnacle’s efficient market.

Step 6 — Payout rate (quality gate)

payout_rate in the API response is not the raw Pinnacle TRJ. It is a distinct quality metric: the TRJ of the market with the bookmaker’s odds substituted in for its own Pinnacle side, keeping raw Pinnacle odds for all other sides.
# 2-way market (spread, total, tennis ML)
payout_rate = 1 / (1/bookmaker_odds + 1/pinnacle_opposite_raw)

# 3-way market (football ML on one side)
payout_rate = 1 / (1/bookmaker_odds + 1/pinnacle_draw_raw + 1/pinnacle_opposite_raw)
This measures whether the bookmaker is pricing its side generously relative to Pinnacle’s raw pricing on every other side. A value bet should produce a market with total payout close to 100% when you combine the bookmaker price with Pinnacle’s opposing prices.

Worked example — 2-way

Bookmaker: Over 2.5 @ 2.10
Pinnacle:  Under 2.5 @ 1.88 (raw, not devigged)

payout_rate = 1 / (1/2.10 + 1/1.88)
            = 1 / (0.476 + 0.532)
            = 1 / 1.008
            = 0.992  → 99.2%   ✓ passes quality gate

Worked example — 3-way (fails)

Bookmaker: Home @ 2.40
Pinnacle raw: Draw @ 3.40, Away @ 2.90

payout_rate = 1 / (1/2.40 + 1/3.40 + 1/2.90)
            = 1 / (0.417 + 0.294 + 0.345)
            = 1 / 1.056
            = 0.947  → 94.7%   ✗ below 99% floor → rejected
In the second case, even though the bookmaker offers Home at 2.40 vs Pinnacle’s fair ~2.30, the raw Pinnacle opposing prices are so favorable that the combined market payout is only 94.7%. This indicates the bookmaker’s price isn’t genuinely better than the Pinnacle market when raw opposing odds are considered.

Quality filters applied before the API responds

All results from /api/value-bets have already passed every filter. Nothing is returned that fails any gate:
FilterThresholdWhy
EV ≥ 1%Minimum edgeNoise below this — line movement can eliminate sub-1% edges before placement
EV ≤ 20%Maximum edgeAbove this = almost certainly stale or miscoded odds, not real
EV ≤ 10% (ML / spread)Efficient market capMoneylines and spreads in efficient markets don’t produce 10%+ edges legitimately
Raw Pinnacle TRJ ≤ 1.05Structural sanityAbove 1.05 = duplicate sides or arbitrage data — structurally invalid, not a value bet
payout_rate ∈ [99%, 105%]Quality gateBelow 99% = edge is noise; above 105% = fair odds calculation error
Odds freshness ≤ 15 minStaleness guardRejects outdated bookmaker prices
Both Pinnacle sides presentDevig requirementSingle-side devig produces absurd fair odds — skip
Odds ratio ≤ 1.15×Sanity checkbookmaker_odds / fair_odds > 1.15 = likely data mismatch

Why bets with “3% EV” sometimes don’t appear

The fair odds floor (+1% for all markets, +4% for props) means:
  • A bookmaker offering 3% raw edge over raw devigged Pinnacle on a moneyline needs ~2% net after the floor → passes EV_MIN=1%
  • A bookmaker offering 3% raw edge on a player prop needs ~5% net after the prop floor → does not pass EV_MIN=1%
Additionally, payout_rate < 99% can reject a bet even when EV% is positive — this happens when the bookmaker’s “edge” disappears once you price it against raw (non-devigged) opposing Pinnacle odds.

Formula reference

FormulaExpression
Implied probability1 / decimal_odds
Raw Pinnacle TRJΣ (1 / pinnacle_odds_i)
Fair odds (2-way)(2 × pin) / (2 − pin × (1/TRJ − 1))
Fair odds (3-way)(3 × pin) / (3 − pin × (1/TRJ − 1))
Fair odds floor× 1.01 all markets; × 1.01 × 1.03 props
EV%(bookmaker_odds / fair_odds_final − 1) × 100
Payout rate (2-way)1 / (1/book + 1/pin_opposite)
Payout rate (3-way)1 / (1/book + Σ 1/pin_others)

Value Bets Reference

Full endpoint docs with all response fields.

Best Practices

Polling, freshness checks, and production patterns.