๐ฒ Betting odds with sportsdataverse-py
Welcome! In a few lines of Python you're about to pull live betting odds
from a whole market of sportsbooks โ moneylines, spreads, totals, player
props, scores, even point-in-time history. sportsdataverse.odds wraps
The Odds API v4 and hands you back tidy polars
DataFrames that are ready to model. ๐
If you've used the R package oddsapiR,
the toa_* names will feel right at home. Let's dive in!
๐งฐ The toolboxโ
Every function returns a tidy polars DataFrame by default โ pass
return_as_pandas=True for pandas, or return_parsed=False for the raw JSON.
Here's the whole kit (click any name for the full reference):
| Function | What it gives you | Quota |
|---|---|---|
toa_sports | Every in-season sport/league key (the sport= value) | ๐ free |
toa_sports_odds | Current odds for a sport โ one row per outcome | ๐ณ paid |
toa_event_odds | Odds for a single game, including player props | ๐ณ paid |
toa_event_markets | Which markets a game has on offer | ๐ free |
toa_sports_scores | Live + recently-completed scores | ๐ free |
toa_sports_events | Upcoming + live event list (grab event_ids here) | ๐ free |
toa_sports_participants | Teams / participants for a sport | ๐ free |
toa_sports_odds_history | Historical odds snapshot (paid plans) | ๐ณ paid |
toa_sports_events_history | Historical event snapshot | ๐ณ paid |
toa_event_odds_history | Historical single-game odds | ๐ณ paid |
toa_usage | Your remaining quota (reads cached headers) | ๐ free |
๐ Setupโ
pip install sportsdataverse
The Odds API needs a key โ grab a free one at
the-odds-api.com. Set it once as the
ODDS_API_KEY environment variable (the same name oddsapiR uses) or pass
api_key= to any call. The live cells below run only when a key is present,
so this page is happy either way. ๐
import os
import polars as pl
import sportsdataverse.odds as odds
HAS_KEY = bool(os.environ.get("ODDS_API_KEY"))
print("ODDS_API_KEY set:", HAS_KEY, "โ live cells will" + ("" if HAS_KEY else " NOT") + " run")
ODDS_API_KEY set: True โ live cells will run
๐๏ธ What's on the board?โ
Start with toa_sports โ it lists every sport/league key,
and it's free (doesn't touch your quota). The key column is what you
pass as sport= everywhere else.
if HAS_KEY:
sports = odds.toa_sports(all_sports=True)
out = sports.select([c for c in ["key", "group", "title", "active"] if c in sports.columns]).head(12)
else:
out = "set ODDS_API_KEY to run: odds.toa_sports(all_sports=True)"
out
shape: (12, 4)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโ
โ key โ group โ title โ active โ
โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ bool โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโก
โ americanfootball_cfl โ American Football โ CFL โ true โ
โ americanfootball_ncaaf โ American Football โ NCAAF โ true โ
โ americanfootball_ncaaf_champioโฆ โ American Football โ NCAAF Championship Winner โ true โ
โ americanfootball_ncaaf_fcs โ American Football โ NCAAF FCS โ false โ
โ americanfootball_nfl โ American Football โ NFL โ true โ
โ โฆ โ โฆ โ โฆ โ โฆ โ
โ americanfootball_ufl โ American Football โ UFL โ false โ
โ aussierules_afl โ Aussie Rules โ AFL โ true โ
โ aussierules_aflw โ Aussie Rules โ AFL Women's โ true โ
โ baseball_kbo โ Baseball โ KBO โ true โ
โ baseball_milb โ Baseball โ MiLB โ true โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโ
๐ฐ The main event: live oddsโ
toa_sports_odds is the workhorse. It returns long
format โ one row per event ร bookmaker ร market ร outcome โ which is
exactly the shape you want for filtering and modelling. Knobs:
regionsโ bookmaker regions:us,us2,uk,eu,au(comma-separate to mix).marketsโh2h(moneyline),spreads,totals,outrights, โฆ (comma-separated).odds_formatโamericanordecimal.bookmakersโ pin specific books (takes precedence overregions).
if HAS_KEY:
board = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="h2h,spreads")
keep = ["home_team", "away_team", "bookmaker_key", "market_key", "outcome_name", "outcome_point", "outcome_price"]
out = board.select([c for c in keep if c in board.columns]).head(10)
else:
board = None
out = "set ODDS_API_KEY to run: odds.toa_sports_odds(sport='americanfootball_nfl', regions='us')"
out
shape: (10, 7)
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโ
โ home_team โ away_team โ bookmaker_k โ market_key โ outcome_nam โ outcome_poi โ outcome_pri โ
โ --- โ --- โ ey โ --- โ e โ nt โ ce โ
โ str โ str โ --- โ str โ --- โ --- โ --- โ
โ โ โ str โ โ str โ f64 โ i64 โ
โโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโโชโโโโโโโโโโโโโโก
โ Seattle โ New England โ draftkings โ h2h โ New England โ null โ 145 โ
โ Seahawks โ Patriots โ โ โ Patriots โ โ โ
โ Seattle โ New England โ draftkings โ h2h โ Seattle โ null โ -175 โ
โ Seahawks โ Patriots โ โ โ Seahawks โ โ โ
โ Seattle โ New England โ draftkings โ spreads โ New England โ 3.5 โ -118 โ
โ Seahawks โ Patriots โ โ โ Patriots โ โ โ
โ Seattle โ New England โ draftkings โ spreads โ Seattle โ -3.5 โ -102 โ
โ Seahawks โ Patriots โ โ โ Seahawks โ โ โ
โ Seattle โ New England โ betus โ h2h โ New England โ null โ 150 โ
โ Seahawks โ Patriots โ โ โ Patriots โ โ โ
โ Seattle โ New England โ betus โ h2h โ Seattle โ null โ -175 โ
โ Seahawks โ Patriots โ โ โ Seahawks โ โ โ
โ Seattle โ New England โ betus โ spreads โ New England โ 3.5 โ -120 โ
โ Seahawks โ Patriots โ โ โ Patriots โ โ โ
โ Seattle โ New England โ betus โ spreads โ Seattle โ -3.5 โ 100 โ
โ Seahawks โ Patriots โ โ โ Seahawks โ โ โ
โ Seattle โ New England โ fanduel โ h2h โ New England โ null โ 158 โ
โ Seahawks โ Patriots โ โ โ Patriots โ โ โ
โ Seattle โ New England โ fanduel โ h2h โ Seattle โ null โ -188 โ
โ Seahawks โ Patriots โ โ โ Seahawks โ โ โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโ
๐ณ Cookbook: common odds tasksโ
Because everything is one tidy long frame, the fun stuff is just a few polars expressions away. Twelve recipes you'll reach for constantly โ every live cell is key-guarded, so the page renders fine with or without a key.
Recipe 1 โ Best available moneyline (line shopping ๐)โ
For each team, find the highest moneyline price across every book โ and which book is offering it. Sort by price descending, group, take the top.
if HAS_KEY and board is not None:
h2h = board.filter(pl.col("market_key") == "h2h")
best = (
h2h.sort("outcome_price", descending=True)
.group_by(["home_team", "away_team", "outcome_name"], maintain_order=True)
.agg(pl.first("outcome_price").alias("best_price"), pl.first("bookmaker_key").alias("best_book"))
)
out = best.head(10)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 5)
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ
โ home_team โ away_team โ outcome_name โ best_price โ best_book โ
โ --- โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ i64 โ str โ
โโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโก
โ Los Angeles Rams โ Arizona Cardinals โ Arizona Cardinals โ 650 โ williamhill_us โ
โ Seattle Seahawks โ Arizona Cardinals โ Arizona Cardinals โ 575 โ draftkings โ
โ Buffalo Bills โ Miami Dolphins โ Miami Dolphins โ 500 โ williamhill_us โ
โ San Francisco 49ers โ Miami Dolphins โ Miami Dolphins โ 490 โ draftkings โ
โ San Francisco 49ers โ Arizona Cardinals โ Arizona Cardinals โ 470 โ draftkings โ
โ Green Bay Packers โ Miami Dolphins โ Miami Dolphins โ 470 โ draftkings โ
โ Kansas City Chiefs โ Arizona Cardinals โ Arizona Cardinals โ 450 โ williamhill_us โ
โ Los Angeles Chargers โ Arizona Cardinals โ Arizona Cardinals โ 425 โ betus โ
โ New England Patriots โ Miami Dolphins โ Miami Dolphins โ 425 โ draftkings โ
โ Dallas Cowboys โ Arizona Cardinals โ Arizona Cardinals โ 410 โ draftkings โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโ
Recipe 2 โ Spreads & totals for a slate ๐โ
Ask for markets="spreads,totals" and the outcome_point column carries the
line (the spread number / the over-under total).
if HAS_KEY:
st = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="spreads,totals")
out = (
st.filter(pl.col("bookmaker_key") == st["bookmaker_key"][0])
.select(["home_team", "away_team", "market_key", "outcome_name", "outcome_point", "outcome_price"])
.head(10)
if st.height else "no spreads/totals on the board right now"
)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 6)
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ home_team โ away_team โ market_key โ outcome_name โ outcome_point โ outcome_price โ
โ --- โ --- โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ str โ f64 โ i64 โ
โโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโก
โ Seattle โ New England โ spreads โ New England โ 3.5 โ -118 โ
โ Seahawks โ Patriots โ โ Patriots โ โ โ
โ Seattle โ New England โ spreads โ Seattle Seahawks โ -3.5 โ -102 โ
โ Seahawks โ Patriots โ โ โ โ โ
โ Seattle โ New England โ totals โ Over โ 44.5 โ -105 โ
โ Seahawks โ Patriots โ โ โ โ โ
โ Seattle โ New England โ totals โ Under โ 44.5 โ -115 โ
โ Seahawks โ Patriots โ โ โ โ โ
โ Los Angeles โ San Francisco โ spreads โ Los Angeles Rams โ -3.5 โ -108 โ
โ Rams โ 49ers โ โ โ โ โ
โ Los Angeles โ San Francisco โ spreads โ San Francisco โ 3.5 โ -112 โ
โ Rams โ 49ers โ โ 49ers โ โ โ
โ Los Angeles โ San Francisco โ totals โ Over โ 48.5 โ -105 โ
โ Rams โ 49ers โ โ โ โ โ
โ Los Angeles โ San Francisco โ totals โ Under โ 48.5 โ -115 โ
โ Rams โ 49ers โ โ โ โ โ
โ Pittsburgh โ Atlanta Falcons โ spreads โ Atlanta Falcons โ 3.5 โ -118 โ
โ Steelers โ โ โ โ โ โ
โ Pittsburgh โ Atlanta Falcons โ spreads โ Pittsburgh โ -3.5 โ -102 โ
โ Steelers โ โ โ Steelers โ โ โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
Recipe 3 โ Just one book ๐ฏโ
Pin a single sportsbook with bookmakers=. Great for tracking your book's
line without paying for a whole region.
if HAS_KEY:
dk = odds.toa_sports_odds(sport="americanfootball_nfl", bookmakers="draftkings", markets="h2h")
out = dk.select(["home_team", "away_team", "outcome_name", "outcome_price"]).head() if dk.height else "no lines yet"
else:
out = "needs ODDS_API_KEY"
out
shape: (5, 4)
โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ home_team โ away_team โ outcome_name โ outcome_price โ
โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ i64 โ
โโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโก
โ Seattle Seahawks โ New England Patriots โ New England Patriots โ 145 โ
โ Seattle Seahawks โ New England Patriots โ Seattle Seahawks โ -175 โ
โ Los Angeles Rams โ San Francisco 49ers โ Los Angeles Rams โ -185 โ
โ Los Angeles Rams โ San Francisco 49ers โ San Francisco 49ers โ 154 โ
โ Pittsburgh Steelers โ Atlanta Falcons โ Atlanta Falcons โ 150 โ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
Recipe 4 โ Implied probability & the hold ๐งฎโ
American moneyline prices convert to implied win probability with a tiny formula. Add up both sides and the excess over 100% is the book's hold (the vig). Pure polars math on the frame you already pulled โ no extra API call.
if HAS_KEY and board is not None:
h2h = board.filter(pl.col("market_key") == "h2h")
devig = (
h2h.with_columns(
pl.when(pl.col("outcome_price") < 0)
.then(-pl.col("outcome_price") / (-pl.col("outcome_price") + 100))
.otherwise(100 / (pl.col("outcome_price") + 100))
.alias("implied_prob")
)
.group_by(["home_team", "away_team", "bookmaker_key"], maintain_order=True)
.agg(pl.sum("implied_prob").alias("market_total"))
.with_columns(((pl.col("market_total") - 1) * 100).round(2).alias("hold_pct"))
.sort("hold_pct")
)
out = devig.head(10)
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 5)
โโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโฌโโโโโโโโโโโ
โ home_team โ away_team โ bookmaker_key โ market_total โ hold_pct โ
โ --- โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ f64 โ f64 โ
โโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโชโโโโโโโโโโโก
โ Philadelphia Eagles โ Houston Texans โ williamhill_us โ 1.027778 โ 2.78 โ
โ Indianapolis Colts โ Baltimore Ravens โ lowvig โ 1.030996 โ 3.1 โ
โ Indianapolis Colts โ Baltimore Ravens โ betonlineag โ 1.030996 โ 3.1 โ
โ Seattle Seahawks โ New England Patriots โ lowvig โ 1.031146 โ 3.11 โ
โ Seattle Seahawks โ New England Patriots โ betonlineag โ 1.031146 โ 3.11 โ
โ Arizona Cardinals โ Seattle Seahawks โ williamhill_us โ 1.031668 โ 3.17 โ
โ Pittsburgh Steelers โ Atlanta Falcons โ betonlineag โ 1.031962 โ 3.2 โ
โ Pittsburgh Steelers โ Atlanta Falcons โ lowvig โ 1.031962 โ 3.2 โ
โ Las Vegas Raiders โ Miami Dolphins โ betonlineag โ 1.031962 โ 3.2 โ
โ Las Vegas Raiders โ Miami Dolphins โ lowvig โ 1.031962 โ 3.2 โ
โโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโดโโโโโโโโโโโ
Recipe 5 โ Find the biggest favorite on the board ๐ปโ
Sort the moneyline outcomes by price ascending โ the most negative number is the heaviest chalk on the slate. A classic "find the X" one-liner.
if HAS_KEY and board is not None:
faves = (
board.filter(pl.col("market_key") == "h2h")
.sort("outcome_price")
.select(["home_team", "away_team", "outcome_name", "outcome_price", "bookmaker_key"])
.head(5)
)
out = faves
else:
out = "needs ODDS_API_KEY"
out
shape: (5, 5)
โโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโ
โ home_team โ away_team โ outcome_name โ outcome_price โ bookmaker_key โ
โ --- โ --- โ --- โ --- โ --- โ
โ str โ str โ str โ i64 โ str โ
โโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโก
โ Los Angeles Rams โ Arizona Cardinals โ Los Angeles Rams โ -1000 โ williamhill_us โ
โ Seattle Seahawks โ Arizona Cardinals โ Seattle Seahawks โ -850 โ draftkings โ
โ Los Angeles Rams โ Arizona Cardinals โ Los Angeles Rams โ -800 โ draftkings โ
โ Seattle Seahawks โ Arizona Cardinals โ Seattle Seahawks โ -800 โ williamhill_us โ
โ Buffalo Bills โ Miami Dolphins โ Buffalo Bills โ -800 โ williamhill_us โ
โโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโ
Recipe 6 โ Consensus over/under per game ๐โ
Books disagree by a half-point here and there. Take the median total across every book to get a stable market consensus for each matchup.
if HAS_KEY:
tot = odds.toa_sports_odds(sport="americanfootball_nfl", regions="us", markets="totals")
if tot.height:
consensus = (
tot.filter(pl.col("outcome_name") == "Over")
.group_by(["home_team", "away_team"], maintain_order=True)
.agg(
pl.median("outcome_point").alias("consensus_total"),
pl.col("bookmaker_key").n_unique().alias("n_books"),
)
.sort("consensus_total", descending=True)
)
out = consensus.head(10)
else:
out = "no totals on the board right now"
else:
out = "needs ODDS_API_KEY"
out
shape: (10, 4)
โโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโ
โ home_team โ away_team โ consensus_total โ n_books โ
โ --- โ --- โ --- โ --- โ
โ str โ str โ f64 โ u32 โ
โโโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโชโโโโโโโโโโก
โ Los Angeles Rams โ Buffalo Bills โ 54.0 โ 2 โ
โ Dallas Cowboys โ San Francisco 49ers โ 53.0 โ 2 โ
โ Los Angeles Rams โ Dallas Cowboys โ 53.0 โ 2 โ
โ Dallas Cowboys โ Tampa Bay Buccaneers โ 52.5 โ 3 โ
โ Indianapolis Colts โ Dallas Cowboys โ 52.5 โ 3 โ
โ Washington Commanders โ Cincinnati Bengals โ 52.5 โ 3 โ
โ Detroit Lions โ Chicago Bears โ 52.5 โ 3 โ
โ Indianapolis Colts โ Cincinnati Bengals โ 52.5 โ 3 โ
โ Buffalo Bills โ Detroit Lions โ 52.0 โ 7 โ
โ Dallas Cowboys โ Jacksonville Jaguars โ 52.0 โ 2 โ
โโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโดโโโโโโโโโโ
Recipe 7 โ Just today's slate โฐโ
Narrow the pull to a time window with commence_time_from / commence_time_to
(ISO-8601, UTC). Here: only games kicking off in the next 24 hours.
from datetime import datetime, timedelta, timezone
if HAS_KEY:
now = datetime.now(timezone.utc)
fmt = "%Y-%m-%dT%H:%M:%SZ"
today = odds.toa_sports_odds(
sport="americanfootball_nfl",
regions="us",
markets="h2h",
commence_time_from=now.strftime(fmt),
commence_time_to=(now + timedelta(hours=24)).strftime(fmt),
)
out = (
today.select(["commence_time", "home_team", "away_team"]).unique(maintain_order=True).head(10)
if today.height else "nothing kicks off in the next 24h"
)
else:
out = "set ODDS_API_KEY to run the commence-time filter recipe"
out
'nothing kicks off in the next 24h'
Recipe 8 โ Player props for one game ๐ฏโ
Event-level markets (player props!) live on toa_event_odds.
Grab an event_id from toa_sports_events, then ask
for a prop market like player_pass_tds or player_anytime_td.
if HAS_KEY:
events = odds.toa_sports_events(sport="americanfootball_nfl", return_parsed=False)
if events:
eid = events[0]["id"]
props = odds.toa_event_odds(sport="americanfootball_nfl", event_id=eid, markets="player_pass_tds")
out = props.select([c for c in ["outcome_name", "outcome_description", "outcome_point", "outcome_price"]
if c in props.columns]).head()
else:
out = "no upcoming NFL events right now"
else:
out = "set ODDS_API_KEY to run the player-props recipe"
out
shape: (5, 4)
โโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโ
โ outcome_name โ outcome_description โ outcome_point โ outcome_price โ
โ --- โ --- โ --- โ --- โ
โ str โ str โ f64 โ i64 โ
โโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโก
โ Over โ Sam Darnold โ 1.5 โ 107 โ
โ Under โ Sam Darnold โ 1.5 โ -136 โ
โ Over โ Drake Maye โ 1.5 โ 127 โ
โ Under โ Drake Maye โ 1.5 โ -162 โ
โ Over โ Drake Maye โ 1.5 โ 138 โ
โโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโ
Recipe 9 โ Which markets does a game offer? ๐๏ธโ
Not sure which props are even available? toa_event_markets
lists every market on offer per book โ and it's free. Count them up to
see which sportsbook posts the deepest menu.
if HAS_KEY:
events = odds.toa_sports_events(sport="americanfootball_nfl", return_parsed=False)
if events:
eid = events[0]["id"]
mk = odds.toa_event_markets(sport="americanfootball_nfl", event_id=eid)
out = (
mk.group_by("bookmaker_key").agg(pl.col("market_key").n_unique().alias("n_markets"))
.sort("n_markets", descending=True).head(10)
if mk.height else "no markets posted for this event yet"
)
else:
out = "no upcoming NFL events right now"
else:
out = "set ODDS_API_KEY to run the event-markets recipe"
out
shape: (10, 2)
โโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ bookmaker_key โ n_markets โ
โ --- โ --- โ
โ str โ u32 โ
โโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโก
โ draftkings โ 102 โ
โ fanduel โ 59 โ
โ betrivers โ 48 โ
โ bovada โ 44 โ
โ fanatics โ 32 โ
โ betonlineag โ 30 โ
โ betmgm โ 29 โ
โ williamhill_us โ 23 โ
โ betus โ 6 โ
โ lowvig โ 3 โ
โโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโ
Recipe 10 โ Recent finals & margin of victory ๐โ
toa_sports_scores returns live + recently
completed games (days_from=1..3, free). Keep the completed ones and
show the final scoreline โ handy for grading bets after the fact.
if HAS_KEY:
sc = odds.toa_sports_scores(sport="americanfootball_nfl", days_from=3)
keep = [c for c in ["completed", "home_team", "away_team", "scores", "last_update"] if c in sc.columns]
if sc.height and "completed" in sc.columns:
out = sc.filter(pl.col("completed")).select(keep).head(10)
else:
out = sc.select(keep).head(10) if sc.height else "no recent scores right now"
else:
out = "set ODDS_API_KEY to run: odds.toa_sports_scores(sport='americanfootball_nfl', days_from=3)"
out
shape: (0, 5)
โโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโโโโฌโโโโโโโโโฌโโโโโโโโโโโโโโ
โ completed โ home_team โ away_team โ scores โ last_update โ
โ --- โ --- โ --- โ --- โ --- โ
โ bool โ str โ str โ str โ str โ
โโโโโโโโโโโโโชโโโโโโโโโโโโชโโโโโโโโโโโโชโโโโโโโโโชโโโโโโโโโโโโโโก
โโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโโโโดโโโโโโโโโดโโโโโโโโโโโโโโ
Recipe 11 โ Tour several leagues at once ๐โ
The sport= key is the only thing that changes between leagues, so one loop
counts the upcoming events across a handful of them. toa_sports_events is
free, so this sweep costs you nothing.
if HAS_KEY:
keys = ["americanfootball_nfl", "basketball_nba", "icehockey_nhl", "baseball_mlb"]
rows = []
for k in keys:
evs = odds.toa_sports_events(sport=k, return_parsed=False)
rows.append({"sport": k, "upcoming_events": len(evs) if isinstance(evs, list) else 0})
out = pl.DataFrame(rows).sort("upcoming_events", descending=True)
else:
out = "set ODDS_API_KEY to tour leagues with odds.toa_sports_events(sport=...)"
out
shape: (4, 2)
โโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโ
โ sport โ upcoming_events โ
โ --- โ --- โ
โ str โ i64 โ
โโโโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโก
โ americanfootball_nfl โ 272 โ
โ basketball_nba โ 41 โ
โ icehockey_nhl โ 32 โ
โ baseball_mlb โ 23 โ
โโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโ
Recipe 12 โ Who's in the league? (participants ๐ฅ)โ
toa_sports_participants lists every team /
participant for a sport โ the lookup table you join odds against by name.
Also free.
if HAS_KEY:
parts = odds.toa_sports_participants(sport="americanfootball_nfl")
keep = [c for c in ["full_name", "id", "abbreviation"] if c in parts.columns]
out = parts.select(keep if keep else parts.columns).head(10) if parts.height else "no participants listed"
else:
out = "set ODDS_API_KEY to run: odds.toa_sports_participants(sport='americanfootball_nfl')"
out
shape: (10, 2)
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ full_name โ id โ
โ --- โ --- โ
โ str โ str โ
โโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโก
โ Arizona Cardinals โ par_01hqmkr1xsfxmrj5pdq0f23asx โ
โ Atlanta Falcons โ par_01hqmkr1xtexkbhkq7ct921rne โ
โ Baltimore Ravens โ par_01hqmkr1xvev9rf557fy09k2cx โ
โ Buffalo Bills โ par_01hqmkr1xwe6prjwr3j4gpqwx8 โ
โ Carolina Panthers โ par_01hqmkr1xxf2ebbqzb95qzxxxm โ
โ Chicago Bears โ par_01hqmkr1xye20ahvp8fr2bvt74 โ
โ Cincinnati Bengals โ par_01hqmkr1xze7xbceshy9tka512 โ
โ Cleveland Browns โ par_01hqmkr1y0ez5bem3gdncd8a0d โ
โ Dallas Cowboys โ par_01hqmkr1y1esas88pmaxe87by4 โ
โ Denver Broncos โ par_01hqmkr1y2e15tjsz9afcsj7da โ
โโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โฝ Mind your quotaโ
Paid calls cost credits (every 10 bookmakers ร market โ 1 credit). After any
call, toa_usage reads the most recent
x-requests-remaining / x-requests-used headers without spending a
request โ handy to drop at the end of a script.
odds.toa_usage() if HAS_KEY else "set ODDS_API_KEY to track quota with odds.toa_usage()"
shape: (1, 3)
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโ
โ requests_remaining โ requests_used โ last_cost โ
โ --- โ --- โ --- โ
โ i64 โ i64 โ i64 โ
โโโโโโโโโโโโโโโโโโโโโโชโโโโโโโโโโโโโโโโชโโโโโโโโโโโโก
โ 4957742 โ 42258 โ 1 โ
โโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโดโโโโโโโโโโโโ
โณ Time travel: historical oddsโ
On a paid plan you can pull point-in-time snapshots โ perfect for closing
line value studies. Pass a date= ISO-8601 timestamp; the snapshot is
unwrapped to the same long format and every row is stamped with the snapshot
time.
| Function | Snapshot ofโฆ |
|---|---|
toa_sports_odds_history | a whole sport's odds at date |
toa_sports_events_history | the events at date |
toa_event_odds_history | one game's odds at date |
odds.toa_sports_odds_history(sport="americanfootball_nfl", date="2023-11-29T22:45:00Z")
๐ Where to nextโ
- Pass
return_as_pandas=Truefor a pandas frame, orreturn_parsed=Falsefor raw JSON. - Full reference: the Betting โ Odds section in the sidebar.
- R user? The same surface lives in oddsapiR.
Happy modelling โ may your closing line value be ever positive! ๐