Turn raw odds data into actionable insights using Python and pandas. This tutorial fetches live odds from the FieldFunded API, loads them into DataFrames, and runs analysis — implied probabilities, margin calculation, and value detection.
import requestsimport pandas as pdAPI_KEY = "your_api_key_here"BASE = "https://api.fieldfunded.com/v1"H = {"X-API-Key": API_KEY}# Get Premier League eventsevents = requests.get( f"{BASE}/events", headers=H, params={"sport": "soccer", "league": "england_epl"}).json()# Build a flat list of all match winner oddsrows = []for event in events["events"][:10]: odds = requests.get( f"{BASE}/events/{event['id']}/odds", headers=H ).json() for market in odds["markets"]: if "1x2" not in market["name"].lower() and \ "winner" not in market["name"].lower(): continue for sel in market["selections"]: rows.append({ "match": f"{event['home_team']} vs {event['away_team']}", "kickoff": event["commence_time"], "selection": sel["name"], "odds": sel["odds"], "market_id": market["id"], "selection_id": sel["id"], })df = pd.DataFrame(rows)print(df.head(9))
Output:
match kickoff selection odds0 Manchester United vs Liverpool 2026-05-10T15:00:00Z Man United 3.401 Manchester United vs Liverpool 2026-05-10T15:00:00Z Draw 3.602 Manchester United vs Liverpool 2026-05-10T15:00:00Z Liverpool 2.103 Arsenal vs Aston Villa 2026-05-10T17:30:00Z Arsenal 1.554 Arsenal vs Aston Villa 2026-05-10T17:30:00Z Draw 4.205 Arsenal vs Aston Villa 2026-05-10T17:30:00Z Aston Villa 5.80
# Implied probability = 1 / decimal_oddsdf["implied_prob"] = (1 / df["odds"] * 100).round(1)# Group by match to calculate the margin (overround)def calc_margin(group): total_prob = group["implied_prob"].sum() group["margin"] = (total_prob - 100).round(1) return groupdf = df.groupby("match", group_keys=False).apply(calc_margin)print(df[["match", "selection", "odds", "implied_prob", "margin"]].head(6))
Output:
match selection odds implied_prob margin0 Manchester United vs Liverpool Man United 3.40 29.4 5.91 Manchester United vs Liverpool Draw 3.60 27.8 5.92 Manchester United vs Liverpool Liverpool 2.10 47.6 5.93 Arsenal vs Aston Villa Arsenal 1.55 64.5 5.14 Arsenal vs Aston Villa Draw 4.20 23.8 5.15 Arsenal vs Aston Villa Aston Villa 5.80 17.2 5.1
The margin (5-6%) represents the bookmaker’s edge. Lower margins mean better odds for bettors.
A “value bet” is when you believe the true probability is higher than the implied probability. Use your own model or estimates:
# Example: your model's probability estimatesyour_model = { "Man United": 32.0, # Your model says 32%, book says 29.4% "Draw": 26.0, # Model says 26%, book says 27.8% "Liverpool": 42.0, # Model says 42%, book says 47.6% "Arsenal": 68.0, # Model says 68%, book says 64.5%}df["model_prob"] = df["selection"].map(your_model)df["edge"] = (df["model_prob"] - df["implied_prob"]).round(1)# Value bets: where your model gives higher probability than the bookvalue_bets = df[df["edge"] > 0].sort_values("edge", ascending=False)print(value_bets[["match", "selection", "odds", "implied_prob", "model_prob", "edge"]])
Output:
match selection odds implied_prob model_prob edge3 Arsenal vs Aston Villa Arsenal 1.55 64.5 68.0 3.50 Manchester United vs Liverpool Man United 3.40 29.4 32.0 2.6
import matplotlib.pyplot as pltdef plot_odds_history(history_df): """Plot odds movement over time for each selection.""" fig, ax = plt.subplots(figsize=(10, 5)) for name, group in history_df.groupby("selection"): ax.plot( range(len(group)), group["odds"].values, marker="o", label=name, linewidth=2, ) ax.set_xlabel("Snapshot") ax.set_ylabel("Decimal Odds") ax.set_title("Odds Movement Over Time") ax.legend() ax.grid(True, alpha=0.3) plt.tight_layout() plt.savefig("odds_movement.png", dpi=150) print("Chart saved to odds_movement.png")# plot_odds_history(history)
# Save to CSVdf.to_csv("epl_odds.csv", index=False)print(f"Saved {len(df)} rows to epl_odds.csv")# Save to Excel with multiple sheetswith pd.ExcelWriter("odds_analysis.xlsx") as writer: df.to_excel(writer, sheet_name="All Odds", index=False) value_bets.to_excel(writer, sheet_name="Value Bets", index=False) print("Saved to odds_analysis.xlsx")