Needs the Ultra plan Python 3 API calls

Plot an odds movement chart

Every recorded price for a match, from the opening quote weeks before kickoff to the last in-play tick, drawn as one chart.

The finished chart

Sample output: one Premier League match, drawn from the API's own ticks.

Fulham 1–1 Man Utd · Bet365 1X2 · 20 Sep 2026

Fulham Draw Man Utd
1.2 1.5 2 3 5 10 20 50 Kickoff → ← Pre-match 1–0 1–1
Price Home Draw Away Recorded (UTC)
Opening 3.6 3.7 1.9 5 Sep 18:26
Closing 3.6 3.8 1.95 20 Sep 15:14
Last in-play 51 1.071 9 20 Sep 17:18

211 ticks, 15 before kickoff and 196 in play. Sample captured 8 October 2026 from GET /v1/fixtures/3197771745/odds/history?market=1x2

The API calls behind it

  1. 1
    GET /v1/leagues?search=Premier League&country=GB-ENG

    Find the league id. Look it up once and keep it. Reference →

  2. 2
    GET /v1/leagues/{id}/fixtures?status=finished&per_page=1

    The most recent finished match. Fixtures come newest first. Reference →

  3. 3
    GET /v1/fixtures/{id}/odds/history?market=1x2&per_page=500

    Every recorded 1X2 price, oldest first, each with the minute and the score at that moment. Reference →

What it takes to run

  • Odds movement history is an Ultra feature ($25/mo). Free and Pro keys get a 403 insufficient_plan on this endpoint.
  • Three requests per chart: find the league, find the match, read its ticks. A page holds 500 ticks, more than most matches have.
  • Ultra allows 40 requests / min.
Compare plans

The code

Install the client, save the script, run it with your key.

pip install fivedollarfootball matplotlib
import os
import matplotlib.pyplot as plt
from fivedollarfootball import Client

client = Client(os.environ["FIVEDOLLARFOOTBALL_API_KEY"])

# 1. The most recent finished Premier League match.
leagues = client.leagues(search="Premier League", country="GB-ENG")
league = next(l for l in leagues if l["name"] == "England Premier League")
match = client.league_fixtures(league["id"], status="finished", per_page=1)[0]
name = f'{match["teams"]["home"]["name"]} v {match["teams"]["away"]["name"]}'

# 2. Every recorded 1X2 price, oldest first, across all pages.
history = client.iter_all(
    client.odds_history, fixture_id=match["id"], market="1x2", per_page=500
)
ticks = [t for t in history if t["home"]]
kickoff = next((i for i, t in enumerate(ticks) if t["minute"] is not None), len(ticks))

# 3. One step line per outcome. A log scale keeps the in-play swings readable.
for side in ("home", "draw", "away"):
    plt.step(range(len(ticks)), [t[side] for t in ticks], where="post", label=side)
plt.axvline(kickoff, linestyle="--", color="grey")
plt.yscale("log")
plt.title(f"{name}, Bet365 1X2")
plt.xlabel("tick (dashed line = kickoff)")
plt.legend()
plt.savefig("movement.png", dpi=150)

print(f"{name}: {len(ticks)} ticks, {kickoff} pre-match, {len(ticks) - kickoff} in-play")
Fulham v Man Utd: 211 ticks, 15 pre-match, 196 in-play
FIVEDOLLARFOOTBALL_API_KEY=fb_live_your_key python odds_movement.py

The full project is on GitHub: 5dollarfootball-api/football-odds-movement-chart →

Take it further

  • Change market to "asian", "goalline" or "corner" to chart a line and its two prices instead.
  • Pass bookmaker="pinnacle" (or any slug from client.bookmakers()) to chart another book.
  • Each tick carries the score at that moment: mark the goals and measure how far each one moved the price.
  • Turn each tick into probabilities (1 / price, normalized) to chart win probability instead of odds.
  • Compare the first and the last pre-match tick for the opening-to-closing move.

Frequently asked questions

Ultra, at $25/mo. Odds movement history is the one endpoint in this example that Free and Pro keys cannot read; they get an explicit 403 insufficient_plan rather than an empty list. Current, opening and closing odds are on every plan through /v1/fixtures/{id}/odds.

It depends on the match and the market. A typical Premier League fixture carries around 200 Bet365 ticks on a main market: 15 to 20 before kickoff, starting weeks out, and the rest in play, seconds apart around goals.

Yes. Bet365 carries thirteen history markets, including Asian handicap, goal line, corner line and card line. Other bookmakers carry 1X2, Asian handicap, goal line and corner line; pass one bookmaker slug per call.

Start building for free

Get a working API key in under a minute. No credit card, no sales call.