Skip to Content
SDKsPython

Python SDK

Das offizielle sharpapi Python-Paket bietet typisierten Zugriff auf alle SharpAPI-Endpunkte mit Pydantic-Modellen, SSE-Streaming und vollständiger IDE-Autovervollständigung.

Installation

pip install sharpapi

Mit optionaler pandas-Unterstützung:

pip install sharpapi[pandas]

Erfordert Python 3.9+.

Schnellstart

from sharpapi import SharpAPI client = SharpAPI("sk_live_xxx") # Arbitrage opportunities arbs = client.arbitrage.get(min_profit=1.0, league="nba") for arb in arbs.data: print(f"{arb.profit_percent:.2f}% profit — {arb.event_name}") for leg in arb.legs: print(f" {leg.sportsbook}: {leg.selection} @ {leg.odds_american} ({leg.stake_percent:.1f}%)") # +EV opportunities evs = client.ev.get(min_ev=3.0, sport="basketball") for opp in evs.data: print(f"+{opp.ev_percentage:.1f}% EV on {opp.selection} @ {opp.sportsbook}") if opp.kelly_percent: print(f" Kelly: {opp.kelly_percent:.2f}%, Confidence: {opp.confidence_score}") # Best odds across sportsbooks odds = client.odds.best(league="nba", market="moneyline") for line in odds.data: print(f"{line.home_team} vs {line.away_team}: {line.selection} {line.odds_american}")

Ressourcen

Odds

# Full snapshot with filters client.odds.get(sport="basketball", league="nba", limit=100) # Best odds per selection across books client.odds.best(league="nfl", market="moneyline") # Side-by-side comparison for an event client.odds.comparison(event_id="evt_abc123") # Batch lookup client.odds.batch(event_ids=["evt_abc123", "evt_def456"])

+EV-Gelegenheiten (Pro+)

evs = client.ev.get( min_ev=2.0, sportsbook="draftkings", league="nba", sort="-ev", # Highest EV first max_odds_age=60, # Only fresh odds limit=50, ) for opp in evs.data: print(f"+{opp.ev_percentage:.1f}% on {opp.selection} @ {opp.sportsbook}") print(f" Fair probability: {opp.fair_probability}") print(f" Devig: {opp.devig_method} via {opp.sharp_book}") print(f" Kelly: {opp.kelly_percent:.2f}%") print(f" Confidence: {opp.confidence_score}/100")

Arbitrage (Hobby+)

arbs = client.arbitrage.get( min_profit=0.5, sport="basketball", group="best", # One per event+market max_odds_age=30, # Only fresh odds ) for arb in arbs.data: if arb.possibly_stale: continue # Skip stale opportunities print(f"{arb.profit_percent:.2f}% — {arb.event_name}") if arb.game_state: gs = arb.game_state print(f" Live: {gs.period} {gs.clock} ({gs.score_home}-{gs.score_away})") for leg in arb.legs: print(f" {leg.sportsbook}: {leg.selection} @ {leg.odds_american} → stake {leg.stake_percent:.1f}%")

Middles (Pro+)

middles = client.middles.get(sport="football", min_size=3.0, sort="quality") for mid in middles.data: print(f"{mid.event_name} — gap: {mid.middle_size} pts") if mid.side1 and mid.side2: print(f" {mid.side1.book}: {mid.side1.selection} {mid.side1.line} @ {mid.side1.odds.american}") print(f" {mid.side2.book}: {mid.side2.selection} +{mid.side2.line} @ {mid.side2.odds.american}") print(f" Hit probability: {mid.middle_probability:.1%}") print(f" Expected value: ${mid.expected_value:.2f}") print(f" Key numbers: {mid.key_numbers}")

Low Hold

low_holds = client.low_hold.get(max_hold=2.0, sport="basketball") for lh in low_holds.data: print(f"{lh.event_name}: {lh.hold_percentage:.2f}% hold")

Referenzdaten

client.sports.list() client.leagues.list(sport="basketball") client.sportsbooks.list() client.events.list(league="nba", live=True) client.events.search("Lakers")

Konto

info = client.account.me() print(f"Tier: {info.key['tier']}") print(f"Rate limit: {info.limits.requests_per_minute} req/min") print(f"Features: EV={info.features.ev}, Arb={info.features.arbitrage}")

SSE-Streaming

Echtzeit-Streaming mit Handler-basierten oder Iterator-basierten Mustern.

Wichtig: odds:update-Ereignisse sind Deltas — sie enthalten nur Quoten, die sich geändert haben. Ihr Client muss den lokalen Zustand verwalten und Aktualisierungen in diesen einfügen. Wenn jedes Ereignis als vollständiger Snapshot behandelt wird, entstehen fehlerhafte Daten.

Handler-basiert (Decorator-Muster)

stream = client.stream.opportunities(league="nba", min_ev=3.0) @stream.on("ev:detected") def on_ev(data): for opp in data: if not opp.get("possibly_stale"): print(f"+EV: {opp['selection']} {opp['ev_percentage']}% @ {opp['sportsbook']}") @stream.on("arb:detected") def on_arb(data): for arb in data: print(f"Arb: {arb['profit_percent']}% — {arb['event_name']}") @stream.on("snapshot:complete") def on_ready(data): print(f"Ready: {data['total_odds']} odds from {', '.join(data['books'])}") stream.connect() # Blocks, processing events

Iterator-basiert

stream = client.stream.all(sport="basketball") for event_type, data in stream.iter_events(): if event_type == "ev:detected": for opp in data: print(f"+EV: {opp['ev_percentage']}%") elif event_type == "arb:detected": for arb in data: print(f"Arb: {arb['profit_percent']}%") elif event_type == "snapshot:complete": print("Stream ready")

Vollständige Zustandsverwaltung

odds_map = {} # Keyed by odds line ID stream = client.stream.all(league="nba") @stream.on("snapshot") def on_snapshot(data): for key, value in data.items(): if isinstance(value, list) and key not in ("ev", "arbitrage", "middles", "low_hold"): for odds in value: odds_map[odds["id"]] = odds @stream.on("odds:update") def on_update(data): # DELTA — merge into local state for book, odds_list in data.items(): if isinstance(odds_list, list): for odds in odds_list: odds_map[odds["id"]] = odds @stream.on("odds:removed") def on_removed(data): for odds_id in data.get("ids", []): odds_map.pop(odds_id, None) @stream.on("connected") def on_connected(data): if data.get("reconnected"): odds_map.clear() # Clear stale state on reconnect stream.connect()

Stream-Kanäle

# Odds only client.stream.odds(league="nba") # Opportunities only (EV + arb + middles) client.stream.opportunities(min_ev=3.0) # Everything client.stream.all(sport="basketball") # Single event client.stream.event("evt_abc123")

Datenqualität

Jede Gelegenheit enthält Metadaten zur Veraltung:

arbs = client.arbitrage.get() for arb in arbs.data: # Skip stale or suspicious opportunities if arb.possibly_stale: print(f"Stale ({arb.oldest_odds_age_seconds}s old)") continue if "LIVE_HIGH_PROFIT_SUSPICIOUS" in arb.warnings: print("Phantom arb — skipping") continue print(f"Actionable: {arb.profit_percent}%")

Rate Limits

Informationen zu Rate Limits sind nach jeder Anfrage verfügbar:

response = client.odds.get() rl = client.rate_limit print(f"{rl.remaining}/{rl.limit} requests remaining (tier: {rl.tier})")

Fehlerbehandlung

from sharpapi import ( SharpAPI, AuthenticationError, TierRestrictedError, RateLimitedError, ) client = SharpAPI("sk_live_xxx") try: evs = client.ev.get() except AuthenticationError: print("Invalid API key") except TierRestrictedError as e: print(f"Upgrade to {e.required_tier} for this feature") except RateLimitedError as e: print(f"Rate limited — retry after {e.retry_after}s")

Hilfsfunktionen zur Quotenumrechnung

from sharpapi import american_to_decimal, american_to_probability, decimal_to_american american_to_decimal(-110) # 1.909 american_to_decimal(150) # 2.5 american_to_probability(-110) # 0.524 decimal_to_american(2.5) # 150

Context Manager

with SharpAPI("sk_live_xxx") as client: arbs = client.arbitrage.get() # HTTP client automatically closed on exit

Typsicherheit

Alle Antworten verwenden Pydantic-Modelle mit vollständigen Typhinweisen:

from sharpapi import EVOpportunity, ArbitrageOpportunity # IDE autocomplete works on all fields arbs = client.arbitrage.get() arb: ArbitrageOpportunity = arbs.data[0] arb.profit_percent # float arb.legs[0].sportsbook # str arb.game_state.period # str | None
Last updated on