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