Production-grade alternative sports data feed — odds, events, futures, settlement for 30 leagues
Project description
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file altsportsdata-3.2.1.tar.gz.
File metadata
- Download URL: altsportsdata-3.2.1.tar.gz
- Upload date:
- Size: 63.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eef07fbcf0277739000de97a71fd28a4db39857f67ac977de37e1f7ce6e9be3b
|
|
| MD5 |
e9a6f7cfe300d49e991faffdf540f186
|
|
| BLAKE2b-256 |
47c9248af3d18ff0a11145262087a3084dfeae82297ff95b8b05edd1f4c150ba
|
File details
Details for the file altsportsdata-3.2.1-py3-none-any.whl.
File metadata
- Download URL: altsportsdata-3.2.1-py3-none-any.whl
- Upload date:
- Size: 54.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.10
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
18b439d85e7aee39617ee074af0ee4c055854cb3ba87f73550bacfc45eab4fa9
|
|
| MD5 |
8069d86466c58e260d3fb3f475cf9a2b
|
|
| BLAKE2b-256 |
5119dc8e150e2accbf92c825c1748e4454bf23be4d14b1348067640336ff66b0
|