AltSportsData SDK
Production-grade alternative sports data feed — odds, events, futures, settlement for 30 leagues.
Original model-generated probabilities for sports nobody else can price. Built for prediction markets, DFS platforms, and sportsbooks.
pip install altsportsdata
Quick Start
from altsportsdata import AltSportsData
client = AltSportsData(api_key="your_key")
# Discover what's available — every response is a DataFrame
leagues = client.get_leagues()
print(leagues)
league name data_shape archetype market_count markets
────────── ────────────────────────────────── ────────── ──────────────── ──────────── ────────────────────────
spr Supercross field racing 6 matchup, moneyline, ...
wsl World Surf League bracket heat_elimination 6 heat_winner, matchup...
bkfc Bare Knuckle Fighting Championship match combat 1 heat_winner
f1 Formula 1 field racing 9 matchup, moneyline, ...
# Scope to a league — instant self-documenting discovery
spr = client.get_league("spr")
spr.data_shape # → "field" (large field, position markets)
spr.archetype # → "racing"
spr.markets # → ["matchup", "moneyline", "podium", "show", ...]
spr.describe() # → pretty ASCII market menu with method names
# Get odds — straight to DataFrame
events = spr.get_events(status="upcoming")
odds = spr.get_moneylines(events[0].id)
print(odds) # clean table
odds.df # pandas DataFrame
For Prediction Markets (Kalshi, Polymarket)
Fair probabilities, vig-free, summing to 1.0. Ready for contract creation.
client = AltSportsData(api_key="your_key", odds_format="probability")
spr = client.get_league("spr")
# What kind of contracts should I create?
spr.data_shape # → "field" — many binary contracts per event
hints = spr.contract_hints
hints["contract_types"] # → ["outright_winner", "top_n_finish", "exacta", "head_to_head"]
hints["probability_shape"] # → "long-tail (favorite ~15-40%, field ~1-10% each)"
hints["settlement"] # → "Position-based — clear winner, top-N verifiable"
Fair Probabilities (vig-removed)
Raw API odds include bookmaker margin. get_fair_probabilities() removes the
vig so probabilities sum to exactly 1.0 — ready for contract pricing.
probs = spr.get_fair_probabilities(event_id)
print(probs)
Fair Probabilities (margin=61.0%)
athlete fair_probability raw_odds margin outcome_id
────────────────── ──────────────── ──────── ────── ──────────────────────────────────
Eli Tomac 0.3069 2.02 61 7247a2d1-6a0e-4ef1-...
Hunter Lawrence 0.2333 2.66 61 69a9aa04-3ea4-416d-...
Ken Roczen 0.1459 4.26 61 d31567d2-65da-48aa-...
Cooper Webb 0.0908 6.84 61 682ab924-2572-46ac-...
# Probabilities sum to exactly 1.0
total = sum(p["fair_probability"] for p in probs)
# → 1.000000
# Create contracts from the data
for p in probs:
create_contract(
question=f"Will {p['athlete']} win Indianapolis Supercross?",
probability=p["fair_probability"],
settlement_id=p["outcome_id"],
)
Fair Matchup Probabilities
Head-to-head matchups devigged per pair — each pair sums to 1.0:
matchups = spr.get_fair_matchup_probabilities(event_id)
print(matchups)
Fair Matchup Probabilities
player1 fair_prob1 player2 fair_prob2 margin
──────────────── ────────── ─────────────── ────────── ──────
Cooper Webb 0.4046 Ken Roczen 0.5954 6.98
Eli Tomac 0.5620 Hunter Lawrence 0.4380 7.19
Data Shapes — Know What Contracts to Create
Every league has a data shape that tells you the contract structure:
| Shape | Leagues | Contract Pattern |
|---|---|---|
field |
F1, Supercross, NHRA, Disc Golf... (12) | Many binary: "Will X win?", "Top 3?", "Exacta?" |
match |
BKFC, MASL, Power Slap, NLL... (12) | One binary per matchup: "Will A beat B?" |
bracket |
WSL, SLS, Formula Drift (3) | Layered: heat-level + event-level contracts |
f1 = client.get_league("f1")
f1.data_shape # → "field"
f1.contract_hints # → full contract guidance
bkfc = client.get_league("bkfc")
bkfc.data_shape # → "match"
wsl = client.get_league("wsl")
wsl.data_shape # → "bracket"
Settlement for Contract Resolution
result = client.get_settlement(event_id)
for name, mkt in result["markets"].items():
for o in mkt.get("winners", []):
print(f" ✅ {o['athlete']} — settled at {result['settled_at']}")
For DFS Platforms (PrizePicks, Underdog)
client = AltSportsData(api_key="your_key")
# Head-to-head matchups — ready for pick'em
matchups = client.get_matchups(event_id)
for m in matchups:
print(f"{m.player1} ({m.odds1:.2f}) vs {m.player2} ({m.odds2:.2f})")
Cooper Webb (2.31) vs Ken Roczen (1.57)
Eli Tomac (1.66) vs Hunter Lawrence (2.13)
# Player props + totals
props = client.get_player_props(event_id)
totals = client.get_player_totals(event_id, stat="finishingPosition")
# Everything is a DataFrame
matchups.df.to_csv("matchups.csv")
For Sportsbooks (DraftKings, Bet365, Stake)
# American odds
client = AltSportsData(api_key="your_key", odds_format="american")
odds = client.get_moneylines(event_id)
print(odds)
# Fractional odds (UK books)
client = AltSportsData(api_key="your_key", odds_format="fractional")
Market-First Discovery
Sportsbooks think market-first: "Give me all matchups" — not "give me WSL, then check matchups."
# All head-to-head matchups across every league
client.get_markets(market="matchup")
# All moneylines in racing sports
client.get_markets(market="moneyline", archetype="racing")
# All upcoming markets for one league
wsl = client.get_league("wsl")
wsl.get_markets()
Odds Format Conversion
Set once on the client — all responses auto-convert:
client = AltSportsData(api_key="key", odds_format="probability") # Kalshi
client = AltSportsData(api_key="key", odds_format="american") # DraftKings
client = AltSportsData(api_key="key", odds_format="decimal") # Stake (default)
client = AltSportsData(api_key="key", odds_format="fractional") # Bet365
Or convert individual values:
from altsportsdata import convert_odds
convert_odds(2.50, "decimal", "american") # → 150.0
convert_odds(2.50, "decimal", "probability") # → 0.4
convert_odds(150, "american", "decimal") # → 2.5
convert_odds("3/2", "fractional", "probability") # → 0.4
Async Client (Production Infrastructure)
from altsportsdata import AsyncAltSportsData
import asyncio
async def main():
async with AsyncAltSportsData(api_key="key", odds_format="probability") as client:
wsl = client.get_league("wsl")
events = await wsl.get_events(status="upcoming")
# Batch fetch — all events concurrently
ids = [e.id for e in events[:20]]
batch = await client.get_odds_batch(ids, "moneyline")
for eid, odds in batch.items():
if "error" not in odds:
print(f"{eid}: {len(odds.get('eventWinner', []))} outcomes")
asyncio.run(main())
Requires: pip install altsportsdata[async]
Enterprise Reliability
Built for production — automatic retry, rate limit handling, request tracing.
client = AltSportsData(
api_key="key",
max_retries=3, # exponential backoff on 429, 5xx
retry_backoff=0.5, # base delay in seconds
timeout=30, # per-request timeout
)
- Automatic exponential backoff with jitter on 429/5xx
- Respects
Retry-Afterheaders - Request IDs (
X-Request-ID) for debugging - Thread-safe session management
- Context manager support:
with AltSportsData(...) as client:
Full API Reference
Setup
from altsportsdata import AltSportsData
# General client
client = AltSportsData(api_key="your_key")
# League-scoped — auto-filters everything
wsl = client.get_league("wsl")
f1 = client.get_league("f1")
spr = client.get_league("spr")
# With options
client = AltSportsData(
api_key="your_key",
league="wsl",
odds_format="probability",
max_retries=3,
)
Discovery
# All leagues with data shapes and market menus
leagues = client.get_leagues()
print(leagues) # clean table
df = leagues.df # pandas DataFrame
# Filter by archetype or market support
client.get_leagues(archetype="racing")
client.get_leagues(market="matchup")
client.get_leagues(archetype="racing", market="exacta")
# League details
info = client.get_league_info("f1")
info["data_shape"] # → "field"
info["contract_hints"] # → {contract_types, probability_shape, ...}
info["markets"] # → ["moneyline", "matchup", ...]
# Self-documenting league card
spr = client.get_league("spr")
spr.describe() # pretty-prints market menu with methods
spr.data_shape # → "field"
spr.contract_hints # → contract creation guidance
# All market types
client.list_market_types()
# Market catalog with event counts
for lg in client.get_market_catalog():
print(f"{lg['league']:12} upcoming={lg['upcoming_events']}")
Events
events = client.get_events(status="upcoming") # ResultSet with .df
events = client.get_events(status="live")
events = client.get_events(status="completed")
events = client.get_events(status=["live", "upcoming"])
print(events) # clean table
df = events.df # pandas DataFrame
events.to_csv("events.csv")
event = client.get_event("event_id")
participants = client.get_participants("event_id")
Markets (cross-league, prices included)
# Market-first — filter by market type across all leagues
markets = client.get_markets(market="matchup") # all H2H matchups
markets = client.get_markets(market="moneyline", archetype="racing")
# League-scoped
wsl = client.get_league("wsl")
markets = wsl.get_markets() # all market types
markets = wsl.get_markets(status="live") # live only
print(markets) # clean table
df = markets.df # pandas DataFrame
Odds (per event) — all return OddsResult with .df
# Sportsbook
odds = client.get_moneylines("event_id") # event winner
odds = client.get_matchups("event_id") # head-to-head
odds = client.get_totals("event_id") # over/under
odds = client.get_exactas("event_id") # exacta
odds = client.get_podiums("event_id") # top-3
odds = client.get_heat_winners("event_id") # heat winner
odds = client.get_fastest_lap("event_id") # fastest lap
# Prediction market — fair probabilities
probs = client.get_fair_probabilities("event_id") # vig-removed, sums to 1.0
probs = client.get_fair_matchup_probabilities("event_id") # per-matchup devig
probs = client.get_market_probabilities("event_id") # raw probs (with vig)
probs = client.get_podium_probabilities("event_id")
probs = client.get_top_finish_probabilities("event_id", top_n=5)
# DFS
odds = client.get_player_props("event_id")
odds = client.get_player_matchups("event_id")
odds = client.get_player_totals("event_id", stat="points")
# Generic — any market by name or alias
odds = client.get_odds("event_id", "moneyline")
# Every OddsResult has .df
print(odds) # clean table
df = odds.df # pandas DataFrame
odds.to_csv("odds.csv")
Batch Operations
events = client.get_events(league="spr", status="upcoming")
ids = [e.id for e in events]
batch = client.get_odds_batch(ids, "moneyline", max_concurrent=5)
Settlement
result = client.get_settlement("event_id")
# → {event_id, event_name, league, status, settled_at,
# markets: {eventWinner: {outcomes, winners}, headToHead: {...}}}
Live Polling
for update in client.poll_odds(event_id, "moneyline", interval=5, max_polls=60):
print(update)
Futures
client.list_futures()
client.get_futures(tour="tour_id", type="winner")
Odds Conversion (Static)
AltSportsData.convert(2.50, "decimal", "american") # → 150.0
AltSportsData.convert(2.50, "decimal", "probability") # → 0.4
30 Leagues × 3 Data Shapes
Field (large competitor pools)
| Code | League | Markets |
|---|---|---|
f1 |
Formula 1 | moneyline, matchup, top_3, top_5, top_10, exacta, over_under, trifecta |
spr |
Supercross | moneyline, matchup, podium, show, over_under |
motocrs |
Pro Motocross | moneyline, matchup, podium, show, over_under, heat_winner |
nhra |
NHRA Drag Racing | moneyline, matchup, heat_winner, over_under |
dgpt |
Disc Golf Pro Tour | moneyline, matchup, top_3, top_5, over_under, heat_winner |
nrx |
Nitrocross | moneyline, matchup, podium, show, over_under, heat_winner |
worldoutlaws |
World of Outlaws | moneyline, matchup, heat_winner, over_under |
hlrs |
High Limit Racing | moneyline, matchup, heat_winner, over_under |
usac |
USAC Racing | moneyline, matchup, heat_winner, over_under |
motoamerica |
MotoAmerica | moneyline, matchup, over_under |
sprmtcrs |
Supermotocross | moneyline, matchup, podium, heat_winner, over_under |
xgame |
X Games | moneyline, matchup, heat_winner, over_under |
Match (two-sided contests)
| Code | League | Markets |
|---|---|---|
bkfc |
Bare Knuckle FC | heat_winner |
powerslap |
Power Slap | heat_winner |
masl |
Major Arena Soccer | moneyline |
nll |
National Lacrosse League | — |
jaialai |
Jai Alai | moneyline |
byb |
BYB Extreme Fighting | heat_winner |
lux |
LUX Fight League | heat_winner |
raf |
Real American Freestyle | heat_winner |
athletesunlimited |
Athletes Unlimited | moneyline, matchup |
gsoc |
Global Soccer | — |
mltt |
Major League Table Tennis | — |
spectation |
Spectation | heat_winner |
Bracket (heat elimination)
| Code | League | Markets |
|---|---|---|
wsl |
World Surf League | moneyline, matchup, heat_winner, podium, props, show |
sls |
Street League Skateboarding | moneyline, matchup, heat_winner, podium, props, show |
fdrift |
Formula Drift | moneyline, matchup, heat_winner |
Links
License
MIT
Metadata
Release files for altsportsdata 3.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| altsportsdata-3.2.1.tar.gz | 63.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| altsportsdata-3.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 118.1 kB
Release files / altsportsdata-3.2.1.tar.gz
| Download URL | altsportsdata-3.2.1.tar.gz |
|---|---|
| Size | 63.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
eef07fbcf0277739000de97a71fd28a4db39857f67ac977de37e1f7ce6e9be3b
|
|
BLAKE2b-256 checksum How to use checksums |
47c9248af3d18ff0a11145262087a3084dfeae82297ff95b8b05edd1f4c150ba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|
Release files / altsportsdata-3.2.1-py3-none-any.whl
| Download URL | altsportsdata-3.2.1-py3-none-any.whl |
|---|---|
| Size | 54.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
18b439d85e7aee39617ee074af0ee4c055854cb3ba87f73550bacfc45eab4fa9
|
|
BLAKE2b-256 checksum How to use checksums |
5119dc8e150e2accbf92c825c1748e4454bf23be4d14b1348067640336ff66b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.10
|