Juice is the silent killer of betting bankrolls. Every market you bet carries a built-in tax — the vig, the overround, the juice. On a standard -110/-110 spread, you’re paying roughly 4.5% for the privilege of wagering. That sounds small until you multiply it across 2,000 bets per season. The difference between a book charging 4.5% average overround and one charging 6.5% is the difference between a profitable automated strategy and one that bleeds out slowly.

This guide measures vig programmatically across the major offshore sportsbooks. You’ll learn the math behind overround calculation, see real data on which books are tightest by sport, and build a Python scanner that continuously monitors juice across your target books.


Vig Math

Before comparing books, you need to understand what you’re measuring.

Implied Probability from Odds

Every set of odds encodes an implied probability — the book’s stated likelihood of an outcome, inflated by their margin.

American odds to implied probability:

Negative odds (favorite): implied = abs(odds) / (abs(odds) + 100)
  -110 → 110 / 210 = 0.5238 (52.38%)

Positive odds (underdog):  implied = 100 / (odds + 100)
  +150 → 100 / 250 = 0.4000 (40.00%)

Decimal odds: implied probability is simply 1 / decimal_odds. Odds of 1.91 → 1/1.91 = 52.36%.

Overround

The overround is the sum of implied probabilities across all outcomes in a market, minus 100%. In a fair (no-vig) market, the implied probabilities sum to exactly 100%. In practice, they always sum to more — that excess is the book’s margin.

-110 / -110 market:
  Side A: 110/210 = 52.38%
  Side B: 110/210 = 52.38%
  Total:  104.76%
  Overround: 4.76%

A -105/-105 market has ~2.4% overround. A -115/-105 market has ~5.3%. The numbers shift by sport, market type, and book.

No-Vig Fair Odds

To derive the “true” probability from a vigged market, normalize the implied probabilities to sum to 100%:

fair_prob_A = implied_A / (implied_A + implied_B)
fair_prob_B = implied_B / (implied_A + implied_B)
fair_odds_A = 1 / fair_prob_A
fair_odds_B = 1 / fair_prob_B

This strips the book’s margin equally from both sides. The resulting fair odds represent what you’d get in a zero-vig market — your benchmark for measuring whether any given line offers value.

Python: Calculate Vig from a Two-Way Market

def american_to_implied(odds: int) -> float:
    if odds < 0:
        return abs(odds) / (abs(odds) + 100)
    return 100 / (odds + 100)


def decimal_to_implied(odds: float) -> float:
    return 1.0 / odds


def calc_overround(odds_a: float, odds_b: float, fmt: str = "decimal") -> float:
    convert = decimal_to_implied if fmt == "decimal" else american_to_implied
    return (convert(odds_a) + convert(odds_b) - 1.0) * 100


def no_vig_fair_odds(odds_a: float, odds_b: float) -> tuple[float, float]:
    """Return no-vig decimal odds for both sides of a two-way market."""
    imp_a = 1.0 / odds_a
    imp_b = 1.0 / odds_b
    total = imp_a + imp_b
    return (total / imp_a, total / imp_b)


# Example: -110 / -110 in decimal = 1.909 / 1.909
print(calc_overround(1.909, 1.909))        # ~4.76%
print(no_vig_fair_odds(1.909, 1.909))       # (2.0, 2.0) — even money

Vig by Book: The Data

The following ranges are based on aggregated market analysis across thousands of snapshots. Vig varies by sport, market type, time of day, and how close to game time the line is sampled. These are typical ranges — not guarantees.

BetOnline

BetOnline consistently offers some of the tightest lines in the offshore market. NFL spreads typically sit at -110/-110, and you’ll occasionally find -108/-112 or even -105/-115 on high-action games. Their moneyline markets run a bit wider, especially on MLB.

  • NFL/NBA spreads & totals: 4.0–5.5% overround
  • MLB moneylines: 4.5–6.0%
  • Soccer: 5.0–6.5%

Bovada

Bovada’s juice is middle-of-the-pack. Their lines tend to be slower to move, which creates opportunities but also means you’re sometimes betting stale numbers at standard juice. Their NFL spread markets cluster around -110/-110 with occasional -115 on one side.

  • NFL/NBA spreads & totals: 4.5–6.0% overround
  • MLB moneylines: 5.0–6.5%
  • Soccer: 5.5–7.0%

Sportsbetting.ag

Sportsbetting.ag shares a platform with BetOnline — their odds are often identical or within a tick. If you’re shopping between the two, you’ll frequently see the same numbers. The minor differences come from timing: one updates slightly ahead of the other on certain sports.

  • NFL/NBA spreads & totals: 4.0–5.5% overround
  • MLB moneylines: 4.5–6.0%
  • Soccer: 5.0–6.5%

MyBookie

MyBookie typically charges wider margins than the BetOnline/Sportsbetting.ag family. Their spread markets often show -110/-110 but move to -115/-105 faster and more frequently. Moneyline juice is noticeably higher across the board.

  • NFL/NBA spreads & totals: 5.5–7.0% overround
  • MLB moneylines: 6.0–8.0%
  • Soccer: 6.5–8.5%

BetUS

BetUS tends to carry the widest margins among major offshore books. Their spread markets commonly sit at -115/-105 or worse. The juice here is a meaningful drag on any high-volume automated strategy.

  • NFL/NBA spreads & totals: 6.0–7.5% overround
  • MLB moneylines: 6.5–8.5%
  • Soccer: 7.0–9.0%

Comparison Table

BookNFL SpreadsNBA TotalsMLB MoneylinesSoccerAvg. Overround
BetOnline4.0–5.0%4.5–5.5%4.5–6.0%5.0–6.5%~5.0%
Sportsbetting.ag4.0–5.0%4.5–5.5%4.5–6.0%5.0–6.5%~5.0%
Bovada4.5–5.5%5.0–6.0%5.0–6.5%5.5–7.0%~5.7%
MyBookie5.5–6.5%6.0–7.0%6.0–8.0%6.5–8.5%~6.8%
BetUS6.0–7.0%6.5–7.5%6.5–8.5%7.0–9.0%~7.5%

These are approximate ranges based on market analysis, not live guarantees. Vig fluctuates with market conditions, and some books run reduced-juice promotions on specific sports or events. Always verify with current data.


Building a Vig Scanner

Theory is useful. Live data is better. Here’s a VigScanner class that fetches odds from multiple books via The Odds API, calculates the overround per market per book, and produces summary statistics.

import requests
import pandas as pd
from collections import defaultdict
from dataclasses import dataclass


@dataclass
class MarketVig:
    sport: str
    event: str
    book: str
    market: str
    odds_a: float
    odds_b: float
    overround: float


class VigScanner:
    """Scan multiple sportsbooks for vig across sports and markets."""

    API_URL = "https://api.the-odds-api.com/v4/sports/{sport}/odds"

    def __init__(self, api_key: str, books: list[str] | None = None):
        self.api_key = api_key
        self.books = books or [
            "betonlineag", "bovada", "mybookieag", "betus", "sportsbettingag"
        ]

    def _fetch_odds(self, sport: str, markets: str = "h2h,spreads,totals") -> list:
        resp = requests.get(
            self.API_URL.format(sport=sport),
            params={
                "apiKey": self.api_key,
                "regions": "us,us2",
                "markets": markets,
                "oddsFormat": "decimal",
                "bookmakers": ",".join(self.books),
            },
        )
        resp.raise_for_status()
        return resp.json()

    @staticmethod
    def _overround(odds_a: float, odds_b: float) -> float:
        return (1.0 / odds_a + 1.0 / odds_b - 1.0) * 100

    def scan(self, sport: str) -> list[MarketVig]:
        events = self._fetch_odds(sport)
        results = []

        for event in events:
            label = f"{event['away_team']} @ {event['home_team']}"
            for bookmaker in event.get("bookmakers", []):
                book = bookmaker["key"]
                for market in bookmaker.get("markets", []):
                    outcomes = market.get("outcomes", [])
                    if len(outcomes) < 2:
                        continue
                    odds_a = outcomes[0]["price"]
                    odds_b = outcomes[1]["price"]
                    results.append(MarketVig(
                        sport=sport,
                        event=label,
                        book=book,
                        market=market["key"],
                        odds_a=odds_a,
                        odds_b=odds_b,
                        overround=round(self._overround(odds_a, odds_b), 2),
                    ))
        return results

    def summary(self, sports: list[str]) -> pd.DataFrame:
        """Scan multiple sports and return aggregated vig stats by book."""
        all_results = []
        for sport in sports:
            all_results.extend(self.scan(sport))

        df = pd.DataFrame([vars(r) for r in all_results])
        if df.empty:
            return df

        summary = df.groupby(["book", "sport"]).agg(
            mean_vig=("overround", "mean"),
            median_vig=("overround", "median"),
            min_vig=("overround", "min"),
            max_vig=("overround", "max"),
            markets_sampled=("overround", "count"),
        ).round(2).reset_index()

        return summary.sort_values(["sport", "mean_vig"])

Usage

scanner = VigScanner(api_key="your-odds-api-key")

sports = [
    "americanfootball_nfl",
    "basketball_nba",
    "baseball_mlb",
    "soccer_epl",
]
report = scanner.summary(sports)
print(report.to_string(index=False))

Example Output

            book                   sport  mean_vig  median_vig  min_vig  max_vig  markets_sampled
      betonlineag  americanfootball_nfl      4.72        4.55     3.90     5.80               42
   sportsbettingag  americanfootball_nfl      4.78        4.60     3.95     5.85               42
          bovada  americanfootball_nfl      5.31        5.20     4.30     6.50               38
      mybookieag  americanfootball_nfl      6.45        6.30     5.10     7.90               40
           betus  americanfootball_nfl      7.12        7.05     5.80     8.60               36
      betonlineag       basketball_nba      4.90        4.80     4.10     6.00               56
          bovada       basketball_nba      5.50        5.40     4.50     6.80               52
      mybookieag       basketball_nba      6.70        6.55     5.40     8.20               50

The data speaks for itself. BetOnline and Sportsbetting.ag consistently come in 1.5–2.5 percentage points tighter than BetUS and MyBookie. Over thousands of bets, that gap compounds into serious money.


Why Vig Matters for Automated Strategies

If you’re placing 10 bets a month, vig is an annoyance. If your bot is placing 50+ bets per week, vig is a strategic variable that determines whether you’re profitable.

Impact on +EV Detection

Your +EV detection threshold is directly affected by vig. If you’re comparing a book’s line against a Pinnacle no-vig benchmark, the book’s overround sets the floor for how much edge you need to overcome. A 4.5% vig book only requires ~2.3% edge per side to be +EV. A 7% vig book requires ~3.5% per side. The lower-vig book surfaces more +EV opportunities at any given edge threshold.

Impact on Arb Frequency

Arbitrage opportunities appear when the gap between two books exceeds their combined vig. Two books with 4.5% overround each need a total of ~9% price disagreement to produce an arb. Two books with 7% overround each need ~14%. Lower vig across your target books means more arbs, more often.

Impact on CLV Measurement

When you measure closing line value, you’re comparing your bet price against a closing line that still contains vig. Using no-vig closing lines (stripped of overround) gives you a cleaner measurement, but the amount of vig in the market affects how much CLV you need to be profitable. At a 4.5% vig book, +1% CLV covers the margin. At a 7% book, +1% CLV still leaves you underwater.

Bankroll Impact Over Volume

Here’s where the math gets visceral:

Bets Placed4.5% Vig Book Cost6.5% Vig Book CostDifference
100$225$325$100
500$1,125$1,625$500
1,000$2,250$3,250$1,000
5,000$11,250$16,250$5,000

Assumes $100 average bet size. Vig cost = (overround / 2) × stake per bet.

At 5,000 bets — a realistic annual volume for an active automated strategy — the difference between a tight book and a wide one is $5,000 on a $100 average stake. That’s a 5% drag on total handle, transferred straight from your bankroll to the sportsbook. Routing bets to the lowest-vig book is one of the simplest optimizations that directly improves your bottom line.


No-Vig Line Calculator

Stripping the vig from a market gives you the “true” fair odds — the probability the market assigns to each outcome before the book’s margin inflates it. This is essential for comparing lines across books on an apples-to-apples basis.

def no_vig_calculator(odds_a: float, odds_b: float) -> dict:
    """Derive no-vig fair odds and probabilities from a two-way decimal market."""
    imp_a = 1.0 / odds_a
    imp_b = 1.0 / odds_b
    total = imp_a + imp_b
    overround = (total - 1.0) * 100

    fair_prob_a = imp_a / total
    fair_prob_b = imp_b / total
    fair_odds_a = 1.0 / fair_prob_a
    fair_odds_b = 1.0 / fair_prob_b

    return {
        "side_a": {
            "vigged_odds": odds_a,
            "implied_prob": round(imp_a * 100, 2),
            "fair_prob": round(fair_prob_a * 100, 2),
            "fair_odds": round(fair_odds_a, 3),
        },
        "side_b": {
            "vigged_odds": odds_b,
            "implied_prob": round(imp_b * 100, 2),
            "fair_prob": round(fair_prob_b * 100, 2),
            "fair_odds": round(fair_odds_b, 3),
        },
        "overround_pct": round(overround, 2),
    }


# Standard -110 / -110 spread
result = no_vig_calculator(1.909, 1.909)
# side_a: fair_prob=50.0%, fair_odds=2.000
# side_b: fair_prob=50.0%, fair_odds=2.000
# overround: 4.76%

# Lopsided moneyline: -200 / +170 → decimal 1.50 / 2.70
result = no_vig_calculator(1.50, 2.70)
# side_a: fair_prob=63.16%, fair_odds=1.583
# side_b: fair_prob=36.84%, fair_odds=2.714  (slight value if book offers 2.70)
# overround: 3.70%

The no-vig fair odds are your benchmark. If a book offers odds better than the fair line derived from the sharpest available market (typically Pinnacle), that’s a +EV bet. This is the foundation of the +EV betting bot approach — strip Pinnacle’s vig, compare every other book’s raw odds to that benchmark, and bet when the gap is large enough.


What’s Next

Vig analysis is one layer of the sharp betting stack. Combine it with line movement tracking and +EV detection for a complete automated edge: