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
| 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
GET /v1/leagues?search=Premier League&country=GB-ENGFind the league id. Look it up once and keep it. Reference →
-
2
GET /v1/leagues/{id}/fixtures?status=finished&per_page=1The most recent finished match. Fixtures come newest first. Reference →
-
3
GET /v1/fixtures/{id}/odds/history?market=1x2&per_page=500Every 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.
The code
Install the client, save the script, run it with your key.
pip install fivedollarfootball matplotlibimport 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.pyThe 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.
The data behind this example
Football Odds API
One endpoint for European 1X2, Asian handicap, goal line, corner and card odds —...
Asian Handicap Odds API
Asian handicap lines with opening, closing and in-play values — for goals and co...
Goal Line Odds API
Over/under goal lines with opening, closing and in-play values across thousands...
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.