Skip to content

Guides

How do I get WTA odds from open to close by sportsbook in Python?

Every sportsbook's opening and closing price for a WTA match with the margin removed, to see which way the market moved and how much each book charged.

Code verified October 12, 2026. One call to get_match, 2 credits.

The call

match_id comes from get_matches with league: "wta". The qualifying rounds and the WTA 125 matches checked for this guide had an empty odds array, so test for that before you read a row.

import requests
import pandas as pd

API_KEY = "YOUR_API_KEY"

resp = requests.post(
    "https://mcp.acesapi.com/v1/get_match",
    headers={"x-api-key": API_KEY},
    json={
        "match_id": "161284",
        "league": "wta",
    },
    timeout=60,
)
resp.raise_for_status()
data = resp.json()["data"]

def implied(odds):
    return 100 / (odds + 100) if odds > 0 else -odds / (-odds + 100)

m = data["match"]
odds = pd.DataFrame(data["odds"])
for side in ("open", "close"):
    a, b = odds["p1_" + side].map(implied), odds["p2_" + side].map(implied)
    odds["p1_" + side + "_fair"] = a / (a + b)
    odds["margin_" + side] = a + b - 1
odds["p1_move"] = odds["p1_close_fair"] - odds["p1_open_fair"]
print(m["tournament"], m["round"], "|", m["player1"], "v", m["player2"], m["score"])
print(odds[["book", "p1_open", "p1_close", "p1_open_fair", "p1_close_fair", "p1_move", "margin_close"]].round(3).to_string(index=False))
print(m["player1"], "moved", round(odds["p1_move"].mean(), 3), "on average; the winner was",
      m["player1"] if m["winner_id"] == m["player1_id"] else m["player2"])

Replace YOUR_API_KEY with a key from your dashboard. Python needs requests and pandas (pip install requests pandas). JavaScript runs on Node 18 or newer, or in the browser.

What comes back

The data object of the response, trimmed to the first rows. Every field is real output from the run above.

{
  "tour": "WTA",
  "match": {
    "match_id": "161284",
    "tournament_id": "189-2025",
    "tournament": "US Open",
    "season": 2025,
    "surface": "hard",
    "indoor": false,
    "starts_at": "2025-09-06T20:15:00.000Z",
    "match_date": "2025-09-06",
    "draw": "main",
    "round": "Final",
    "round_order": 22,
    "court": "Arthur Ashe Stadium",
    "player1_id": "3038",
    "player1": "Aryna Sabalenka",
    "player1_country": "BLR",
    "seed1": 1,
    "player2_id": "3221",
    "player2": "Amanda Anisimova",
    "player2_country": "USA",
    "seed2": 8,
    "winner_id": "3038",
    "status": "final",
    "outcome": "completed",
    "score": "6-3 7-6(3)",
    "sets1": 2,
    "sets2": 0,
    "games1": 13,
    "games2": 9,
    "note": "(1) Aryna Sabalenka (BLR) bt (8) Amanda Anisimova (USA) 6-3 7-6 (7-3)",
    "sets": [
      {
        "set_no": 1,
        "games1": 6,
        "games2": 3,
        "tiebreak1": null,
        "tiebreak2": null,
        "winner": 1
      },
      {
        "set_no": 2,
        "games1": 7,
        "games2": 6,
        "tiebreak1": 7,
        "tiebreak2": 3,
        "winner": 1
      }
    ]
  },
  "players": [
    {
      "player_id": "3038",
      "name": "Aryna Sabalenka",
      "seed": 1,
      "sets_won": 2,
      "games_won": 13,
      "tiebreaks_won": 1,
      "tiebreak_points_won": 7,
      "sets_won_6_0": 0,
      "rating": {
        "before": 2230,
        "after": 2236,
        "surface_before": 2164,
        "surface_after": 2171
      }
    },
    {
      "player_id": "3221",
      "name": "Amanda Anisimova",
      "seed": 8,
      "sets_won": 0,
      "games_won": 9,
      "tiebreaks_won": 0,
      "tiebreak_points_won": 3,
      "sets_won_6_0": 0,
      "rating": {
        "before": 2087,
        "after": 2079,
        "surface_before": 2007,
        "surface_after": 1998
      }
    }
  ],
  "stats": {
    "sets_played": 2,
    "total_games": 22,
    "tiebreaks": 1,
    "went_the_distance": false,
    "winner_lost_first_set": false,
    "serve_stats": null,
    "serve_stats_note": "ESPN publishes no serve statistics for tennis (aces, double faults, break points), so none are served here."
  },
  "odds": [
    {
      "source": "the_odds_api",
      "book": "888sport",
      "p1_open": -200,
      "p1_close": -188,
      "p2_open": 175,
      "p2_close": 160,
      "games_spread1": null,
      "games_total": null
    },
    {
      "source": "the_odds_api",
      "book": "Betfair Exchange",
      "p1_open": -182,
      "p1_close": -154,
      "p2_open": 180,
      "p2_close": 150,
      "games_spread1": null,
      "games_total": null
    },
    "...5 more"
  ]
}

What to do next

  • get_matches (2 credits). Every match of a tournament or a day, to find the ones with prices.
  • get_ratings (2 credits). Our Elo ratings on the tour, overall or by surface.

More guides

Start with 500 free credits every month

No card. REST or MCP.