Pred-Data Get odds data

Hands-on tutorial

Find arbitrage and +EV prices with Odds-API.io

Use the Odds-API.io /arbitrage-bets and /value-bets endpoints in Python, re-check the margins yourself, scale stakes within bookmaker limits and understand the caveats.

Last updated: · Written and reviewed by Ken Lin

Partner link Partner link — we may earn a commission. See our affiliate disclosure.

Quick answer

Odds-API.io computes both for you: /arbitrage-bets returns cross-bookmaker Arbitrage with the margin and a stake split, and /value-bets returns prices above a sharp-book fair line with their Expected value [1] [2]. This tutorial fetches both, re-checks the maths and lists the limits.

What you need

What you need: The get() helper from Live odds in Python, and a key with at least two bookmakers selected [3].

Get a key: Odds-API.io Partner link

Partner link — we may earn a commission. See our affiliate disclosure.

Code status: The Python in this tutorial was run against the example responses published in the Odds-API.io docs (checked 3 November 2026), not against a live API key. Live responses can carry extra fields; the code only reads documented ones.

1. Fetch arbitrage opportunities

bookmakers is required; minProfit is a percentage; includeEventDetails=true adds teams. Margins are calculated on netOdds where exchange or prediction-market fees apply [1]. The snippet recomputes each margin from the legs as a sanity check.

# reuses get() from the Python tutorial
arbs = get("/arbitrage-bets", bookmakers="Bet365,SingBet,Betano",
           minProfit=1, includeEventDetails="true", limit=50)

for a in arbs:
    # re-check the margin ourselves from the legs (netOdds where fees apply)
    s = sum(1 / float(l.get("netOdds") or l["odds"]) for l in a["legs"])
    mine = (1 - s) / s * 100
    ev = a.get("event", {})
    print(f'{ev.get("home")} v {ev.get("away")} | {a["market"]["name"]} {a["market"].get("hdp", "")}'
          f' | API {a["profitMargin"]:.2f}% vs recomputed {mine:.2f}%')

On the docs' sample (Betfair Exchange over 2.102 net, Bet365 under 2.05) the recomputed margin is 3.78% against the API's 3.79% — a rounding difference.

2. Scale the stake split

optimalStakes are for totalStake (1,000 by default); scale every leg by the same factor and stay under each leg's maxStake [1]. Cross-check with the Arbitrage calculator.

def scale_stakes(arb, bankroll):
    """Scale optimalStakes to a bankroll, keeping every leg under its maxStake."""
    factor = bankroll / arb["totalStake"]
    for st in arb["optimalStakes"]:
        leg = next(l for l in arb["legs"]
                   if l["bookmaker"] == st["bookmaker"] and l["side"] == st["side"])
        if leg.get("maxStake"):
            factor = min(factor, leg["maxStake"] / st["stake"])
    return [{**st, "stake": round(st["stake"] * factor, 2),
             "potentialReturn": round(st["potentialReturn"] * factor, 2)}
            for st in arb["optimalStakes"]]

3. Fetch value bets (+EV)

/value-bets needs one bookmaker; fair odds come from a sharp-book panel and EV = fair probability × odds − 1 [2]. Because expectedValue is a fraction, you can back out the fair probability. Use the Expected value (+EV) calculator and Kelly criterion calculator on any row.

vbs = get("/value-bets", bookmaker="Bet365", sport="football",
          includeEventDetails="true")

for vb in sorted(vbs, key=lambda v: v["expectedValue"], reverse=True)[:10]:
    side = vb["betSide"]
    odds = float(vb["bookmakerOdds"][side])
    fair_p = (vb["expectedValue"] + 1) / odds      # from EV = p x odds - 1
    ev = vb.get("event", {})
    print(f'{ev.get("home")} v {ev.get("away")} | {vb["market"]["name"]} {side} @ {odds}'
          f' | EV {vb["expectedValue"]:.2%} | implied fair p {fair_p:.1%}')

4. Know the limits

Arbitrage results are prematch only and removed as soon as a price moves [1]; bookmakers may limit accounts that take arbs [4]. Value is an estimate against a sharp consensus; track Closing line value to see whether it holds up [5].

Frequently asked questions

How often are opportunities updated?

Value bets are recalculated every 5 seconds and arbitrage opportunities every few seconds, but poll at a rate your plan allows.

Why does my recomputed margin differ slightly?

Rounding: the API's netOdds are rounded strings. Differences of a few hundredths of a percent are expected.

Is a +EV price a sure profit?

No. EV is a long-run average and depends on the fair-probability estimate; individual results vary.

About this guide

Pred-Data publishes independent, source-linked explainers about prediction markets and the AI tools used around them. Every factual claim on this page links to a primary or reputable secondary source, checked on the date shown above. We do not run a trading venue, take bets, or give personal advice.

Author: Ken Lin · Corrections: if you spot an error, we review it and date-stamp the fix.

Affiliate disclosure

Some links on this site (marked “Partner link”) may be affiliate links: if you sign up through them we may earn a commission at no extra cost to you. Partner links use rel="sponsored nofollow" and never change our assessment. Platform links in our comparison tables are plain, non-affiliate links to official sites.

Sources

  1. Arbitrage Bets guide (formula, response format, limitations) — Odds-API.io docs, accessed 2 Nov 2026
  2. Value Bets guide (EV formula, response format, limitations) — Odds-API.io docs, accessed 2 Nov 2026
  3. Quickstart (get a key, first calls, example responses) — Odds-API.io docs, accessed 2 Nov 2026
  4. What Is Arbitrage Betting? Definition & Example — Odds-API.io glossary, accessed 2 Nov 2026
  5. Value Bets API: Track Closing Line Value in Python — Odds-API.io blog, accessed 2 Nov 2026