Providers
A Provider fetches events and odds from a data source and normalises them into the core models. Opensport ships six built-in providers. Swap any without changing your agent code.
Overview
| Provider | Coverage | API key | Install extra |
|---|---|---|---|
MockProvider | In-memory, deterministic, no network | None | None |
PremierLeagueProvider | English Premier League (fixtures + odds) | 2 × free | opensport[http] |
MasseyRatingsProvider | NFL · NBA · MLB · NHL · NCAAF · NCAAB | None | opensport[massey] |
StakeProvider | 20+ sports + esports | Required | opensport[http] |
CloudbetProvider | 20+ sports (free affiliate key) | Required (free) | opensport[http] |
PolymarketProvider | 10+ sports (prediction market prices) | None | opensport[http] |
ProviderRegistry + MultiProvider
Use ProviderRegistry to track which providers are active, and MultiProvider to expose them all through a single BaseProvider interface, with no agent changes required.
Auto-discover from environment variables
from opensport.providers import ProviderRegistry, MultiProvider
registry = ProviderRegistry.from_env()
# Activates providers based on which env vars are set:
# FOOTBALL_DATA_API_KEY + ODDS_API_KEY → PremierLeagueProvider
# MASSEY_SPORTS=nfl,nba (or "all") → MasseyRatingsProvider
# STAKE_API_KEY → StakeProvider
# CLOUDBET_API_KEY → CloudbetProvider
# POLYMARKET_ENABLED=1 → PolymarketProvider
provider = MultiProvider(registry)
events = provider.get_events(sport="soccer")Build manually
from opensport.providers import ProviderRegistry, MultiProvider
from opensport.providers.mock import MockProvider
from opensport.providers.football_data import PremierLeagueProvider
from opensport.providers.massey import MasseyRatingsProvider
from opensport.providers.stake import StakeProvider
from opensport.providers.cloudbet import CloudbetProvider
from opensport.providers.polymarket import PolymarketProvider
registry = (
ProviderRegistry()
.register(MockProvider())
.register(PremierLeagueProvider(fbd_api_key="...", odds_api_key="..."))
.register(MasseyRatingsProvider(sports=["nfl", "nba"]))
.register(StakeProvider(api_key="..."))
.register(CloudbetProvider(api_key="..."))
.register(PolymarketProvider(min_liquidity=500.0))
)
# Enable / disable at runtime
registry.disable("mock")
registry.enable("mock")
# Inspect state
for row in registry.status():
print(row["name"], "→", "ON" if row["enabled"] else "OFF")
# Wire into an agent (unchanged interface)
provider = MultiProvider(registry)
agent = ValueAgent(provider=provider, execution=Simulator(bankroll=1000))MultiProvider merges get_events() across all active providers and routes get_odds(event_id) to the correct provider via the event ID prefix. Provider failures are logged as warnings and skipped. They do not propagate.
MockProvider
Fully in-memory provider with deterministic output controlled by a seed. No API keys, no network calls. Use it for unit testing, tutorials, and sandboxing new strategies.
pip install opensport # zero extra dependenciesfrom opensport.providers.mock import MockProvider
provider = MockProvider(seed=42)
events = provider.get_events()
snap = provider.get_odds(events[0].id)| Parameter | Default | Description |
|---|---|---|
seed | 0 | Integer seed for reproducible event and odds generation |
sports | all | List of sport slugs to generate events for |
n_events_per_sport | 5 | Number of events to generate per sport |
PremierLeagueProvider
English Premier League fixtures, scores, and match-winner odds. Combines two free APIs: Football-Data.org for fixture data and The Odds API for odds. Both offer generous free tiers.
pip install 'opensport[http]'from opensport.providers.football_data import PremierLeagueProvider
provider = PremierLeagueProvider(
fbd_api_key="your-football-data-key",
odds_api_key="your-odds-api-key",
)
events = provider.get_events()
snap = provider.get_odds(events[0].id)
# Auto-activate via environment variables:
# FOOTBALL_DATA_API_KEY=...
# ODDS_API_KEY=...| Parameter | Description |
|---|---|
fbd_api_key | Football-Data.org API key (free tier: 10 req/min) |
odds_api_key | The Odds API key (free tier: 500 req/month) |
timeout | HTTP timeout in seconds (default: 10.0) |
MasseyRatingsProvider
Schedules, scores, and model-derived win-probability odds for the major US sports leagues: NFL, NBA, MLB, NHL, NCAA Football, and NCAA Basketball. No API key required. Data is sourced from masseyratings.com.
pip install 'opensport[massey]'from opensport.providers.massey import MasseyRatingsProvider
provider = MasseyRatingsProvider(sports=["nfl", "nba", "mlb", "nhl"])
events = provider.get_events(sport="nfl")
snap = provider.get_odds(events[0].id)
# Auto-activate via environment variable:
# MASSEY_SPORTS=nfl,nba (comma-separated slugs)
# MASSEY_SPORTS=all (every supported sport)| Parameter | Default | Description |
|---|---|---|
sports | Required | List of slugs: nfl, nba, mlb, nhl, ncaaf, ncaab |
timeout | 15.0 | HTTP timeout in seconds |
StakeProvider
Live bookmaker odds from Stake.com across 20+ sports and esports. Requires a Stake API key.
pip install 'opensport[http]'from opensport.providers.stake import StakeProvider
provider = StakeProvider(
api_key="your-stake-api-key",
sports=["soccer", "basketball"], # None = all available sports
)
events = provider.get_events(sport="soccer")
snap = provider.get_odds(events[0].id)
# Auto-activate via environment variables:
# STAKE_API_KEY=...
# STAKE_SPORTS=soccer,basketball (optional)| Parameter | Default | Description |
|---|---|---|
api_key | Required | Stake.com API key |
sports | None | List of sport slugs to fetch. None = all sports. |
timeout | 10.0 | HTTP timeout in seconds |
CloudbetProvider
Real bookmaker odds from Cloudbet.com across 20+ sports. A free affiliate API key is available. No deposit required.
pip install 'opensport[http]'from opensport.providers.cloudbet import CloudbetProvider
provider = CloudbetProvider(
api_key="your-cloudbet-api-key",
sports=["soccer", "basketball"], # None = all available sports
)
events = provider.get_events(sport="soccer")
snap = provider.get_odds(events[0].id)
# Auto-activate via environment variables:
# CLOUDBET_API_KEY=...
# CLOUDBET_SPORTS=soccer,basketball (optional)| Parameter | Default | Description |
|---|---|---|
api_key | Required | Cloudbet API key (free affiliate key available) |
sports | None | List of sport slugs to fetch. None = all sports. |
timeout | 10.0 | HTTP timeout in seconds |
PolymarketProvider
Consensus probabilities from Polymarket, the world's largest decentralised prediction market. No API key required. Prices reflect the crowd's implied probability rather than a bookmaker's margin-adjusted odds, making them useful as a reference signal for detecting value in traditional bookmaker lines.
pip install 'opensport[http]'from opensport.providers.polymarket import PolymarketProvider
# No API key required (explicit opt-in only)
provider = PolymarketProvider(
sports=["basketball", "soccer"], # None = all supported sports
min_liquidity=500.0, # skip thin markets (USDC)
)
events = provider.get_events(sport="basketball")
snap = provider.get_odds(events[0].id)
winner = snap.market("winner")
if winner:
for o in winner.outcomes:
print(f" {o.label}: {o.decimal_odds:.2f} ({100/o.decimal_odds:.1f}% implied)")
# Auto-activate via environment variables:
# POLYMARKET_ENABLED=1
# POLYMARKET_SPORTS=basketball,soccer (optional)
# POLYMARKET_MIN_LIQUIDITY=500 (optional USDC floor)| Parameter | Default | Description |
|---|---|---|
sports | None | List of sport slugs. None = all supported sports. |
min_liquidity | 0.0 | Skip markets with less than this USDC liquidity. |
timeout | 10.0 | HTTP timeout in seconds. |
Prices are probabilities (0–1) converted to decimal odds: decimal_odds = 1 / probability. Because there is no bookmaker margin, both outcomes in a binary market sum to approximately 1.0.
Supported sport slugs: soccer, basketball, american-football, baseball, ice-hockey, tennis, cricket, mma, boxing. Unknown slugs are passed through as Polymarket native tag slugs (e.g. ncaab, primera-a).
Building a custom provider
Subclass BaseProvider, implement get_events() and get_odds(), and map your data source's native objects into the core models. See the Architecture guide for a full skeleton example.
from opensport.providers.base import BaseProvider
from opensport.core.event import Event
from opensport.core.odds import OddsSnapshot
class MyProvider(BaseProvider):
name = "my_provider" # unique name for registry routing
event_id_prefix = "myprov-" # used by MultiProvider to route get_odds()
def get_events(self, sport=None, competition=None, status=None) -> list[Event]:
... # fetch raw data and return list[Event]
def get_odds(self, event_id: str) -> OddsSnapshot:
... # fetch and return OddsSnapshot