# Python arbitrage calculator with explicit market assumptions

Calculate equal-return stakes from supplied decimal prices. Validate market identity and distinguish an arithmetic fixture from an executable opportunity.

Canonical page: https://getoddsapi.com/guides/python-arbitrage

## Free API key

Get a free GetOdds API key: **1,000 requests per UTC day and 60 per minute, no card**. One key covers REST and the hosted MCP server.

Sign up: https://getoddsapi.com/sign-up?ref=ai-claudebot

## Quickstart

1. Create an account at https://getoddsapi.com/sign-up?ref=ai-claudebot, open https://getoddsapi.com/dashboard and issue a key with the sources you need (draftkings, fanduel, betrivers, prizepicks or underdog). Keep it in a server environment variable named GETODDS_API_KEY.
2. Read current DraftKings NBA spreads with curl:

```bash
curl --fail-with-body "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50" \
  -H "Authorization: Bearer $GETODDS_API_KEY"
```

3. The same request in Python (standard library only):

```python
import json, os, urllib.request

req = urllib.request.Request(
    "https://getoddsapi.com/api/v1/odds?sport=NBA&market=spread&fresh_only=true&limit=50",
    headers={"Authorization": "Bearer " + os.environ["GETODDS_API_KEY"]},
)
with urllib.request.urlopen(req) as res:
    rows = json.load(res)["data"]
for row in rows:
    print(row["away"], "at", row["home"], row["side"], row["line"], row["american"], row["observed_at"])
```

4. Check `observed_at`, `age_seconds` and `stale` on every row before using a price. Full reference: https://getoddsapi.com/docs

## Use with Claude (MCP)

```bash
claude mcp add --transport http getodds https://getoddsapi.com/api/mcp \
  --header "Authorization: Bearer $GETODDS_API_KEY"
```

The MCP tools follow the key's source grants and share its allowance. Setup guide: https://getoddsapi.com/use-with-claude

## Pricing

| Plan | Allowance | Price |
| --- | --- | --- |
| Free key | 1,000 requests a day, 60 a minute | $0, no card |
| Developer Bundle | 10,000 requests or credits a month on each of four sources | $149 a month |

Free development allowance: 1,000 requests per UTC day and 60 per minute per account, with no payment step. Paid: the Developer Bundle at $149 per month, with 10,000 monthly requests or credits on each of four sources.
Details: https://getoddsapi.com/bundle

## Guide


Canonical: https://getoddsapi.com/guides/python-arbitrage
Reviewed: 2026-11-07 UTC

Calculate equal-return stakes from supplied decimal prices. Validate market identity and distinguish an arithmetic fixture from an executable opportunity.

## Establish comparable offers before calculating

The formula requires a complete set of mutually exclusive outcomes for one event, period, line and settlement contract. A three-way football market needs the draw outcome. Quotes must be available at the same time and their books must accept your stake. Different player thresholds cannot fill opposite sides of one contract.

## Run the calculation offline

The example uses two synthetic decimal prices of 2.1. For a total stake of 100, each stake is 50 and the conditional return is 105. This tests the arithmetic, not live book availability.

```python
from math import isfinite

def equal_return_stakes(decimal_odds, bankroll):
    # Supply every mutually exclusive, exhaustive outcome of ONE contract.
    if len(decimal_odds) < 2 or not isfinite(bankroll) or bankroll <= 0:
        raise ValueError("Invalid market or bankroll")
    if any(not isfinite(o) or o <= 1 for o in decimal_odds):
        raise ValueError("Decimal odds must exceed one")
    inverse_sum = sum(1 / o for o in decimal_odds)
    stakes = [bankroll / (o * inverse_sum) for o in decimal_odds]
    return {"stakes": stakes, "return": bankroll / inverse_sum,
            "conditional_profit": bankroll / inverse_sum - bankroll}

# Synthetic arithmetic fixture, NOT current offers.
print(equal_return_stakes([2.1, 2.1], 100))
```

## Account for execution differences

Round stakes to the book’s permitted increments, then recalculate every outcome’s net return. Account for commission, stake caps, void rules and partial fills. A price change between legs can remove the calculated margin. The formula makes no claim of guaranteed profit.

## Connect a real feed only after matching

The current GetOdds gateway has PrizePicks thresholds with odds:null, so it cannot feed this priced-outcome calculator. Obtain verified sportsbook offers from an appropriate source and preserve their identity and timestamps before adapting this example.

## Questions

### Does this scan bookmakers?

No. It calculates on supplied prices. The fixture does not call an API or place bets.

### What does inverse_sum below one mean?

The supplied exhaustive outcomes have a conditional equal-return margin before fees, rounding and execution constraints.

### Can I use two prices from different periods?

No. The outcomes must belong to the same exhaustive market and settlement contract.

## Sources

- [GetOdds arbitrage calculator](https://getoddsapi.com/arbitrage-calculator)
- [Market comparison contract](https://getoddsapi.com/odds-comparison-api)
- [GetOdds developer documentation](https://getoddsapi.com/docs)

Independent product; not affiliated with the operators named. No picks or predicted profits.

---

GetOdds is an independent developer product and is not affiliated with any sportsbook or pick’em operator. Prices describe data, not betting advice.
