Skip to Content
StreamingÜbersicht

Streaming-Übersicht

Echtzeit-Aktualisierungen von Quoten und Opportunitäten über SSE oder WebSocket.

SharpAPI bietet zwei Streaming-Protokolle: SSE (Server-Sent Events) über HTTP und WebSocket für bidirektionale Kommunikation. Beide liefern dieselben Echtzeitdaten — wählen Sie basierend auf Ihrem Anwendungsfall.

Warum Streaming?

REST-Polling verursacht eine Verzögerung von 30-60 Sekunden zwischen Quotenänderungen und deren Sichtbarkeit in Ihrer Anwendung. SSE-Streaming liefert Aktualisierungen mit Sub-Sekunden-Latenz direkt an Ihre Anwendung, sobald sie auftreten.

AnsatzLatenzBandbreiteAnwendungsfall
REST-Polling30-60sHoch (volle Nutzlast bei jeder Abfrage)Gelegentliches Browsen, Dashboards
SSE-Streaming< 1sNiedrig (nur Deltas)Live-Wetten, Benachrichtigungen, automatisierte Systeme
WebSocket< 1sNiedrig (nur Deltas)Bidirektionale Kommunikation, dynamische Filter-Updates

Wesentliche Vorteile

  • Sub-Sekunden-Latenz — Quoten-Updates kommen an, sobald sie erkannt werden
  • Geringere Bandbreite — Es werden nur geänderte Daten gesendet, keine vollständigen Snapshots bei jeder Abfrage
  • Zwei Protokolle — SSE für Einfachheit, WebSocket für bidirektionale Kontrolle
  • Automatische Wiederverbindung — SSE verbindet sich nativ wieder; WebSocket mit einfacher Wiederholungslogik

Wie SSE funktioniert

Server-Sent Events ist ein W3C-Standard für Server-zu-Client-Streaming über HTTP:

Client Server | | |--- GET /api/v1/stream ------->| | | |<-- event: connected ----------| Stream established |<-- event: snapshot -----------| Full current state |<-- event: odds:update --------| Delta update |<-- event: odds:update --------| Delta update |<-- event: ev:detected --------| Opportunity found |<-- event: heartbeat ----------| Keep-alive (every 30s) | ... |

SSE verbindet sich bei einer Trennung automatisch wieder. Der Server verwendet Last-Event-ID, um verpasste Ereignisse erneut abzuspielen.

Anforderungen

TarifStreaming-Zugriff
FreeNicht verfügbar
Hobby + Add-on ($99/Monat)1 Stream (Newer-Wins-Verdrängung)
Pro + Add-on ($99/Monat)1 Stream (Newer-Wins-Verdrängung)
Sharp + Add-on ($99/Monat)1 Stream (Newer-Wins-Verdrängung)
EnterpriseInklusive (individuelle Limits)

Newer-Wins-Verdrängung: Das Öffnen eines zweiten Streams mit demselben API-Schlüssel schließt den ersten. Eine gut verwaltete Verbindung reicht für die meisten Anwendungsfälle aus — siehe Single-Connection-Patterns für Techniken. Flotten-Deployments, die mehrere gleichzeitige Streams benötigen, können über den Vertrieb ein höheres Limit anfordern.

Schnellstart

Browser

// Local odds map — snapshot fills it, deltas merge into it const oddsMap = new Map(); const eventSource = new EventSource( 'https://api.sharpapi.io/api/v1/stream?channel=all&league=nba&api_key=YOUR_KEY' ); eventSource.addEventListener('connected', (e) => { const { stream_id, reconnected } = JSON.parse(e.data); if (reconnected) oddsMap.clear(); console.log('Stream connected:', stream_id); }); eventSource.addEventListener('snapshot', (e) => { const { odds } = JSON.parse(e.data); for (const odd of odds) oddsMap.set(odd.id, odd); console.log('Snapshot chunk:', odds.length, 'odds'); }); eventSource.addEventListener('odds:update', (e) => { const { odds, book } = JSON.parse(e.data); // Delta only contains dynamic fields — merge into local state by ID for (const delta of odds) { const full = oddsMap.get(delta.id); if (full) Object.assign(full, delta); } console.log(`${book}: ${odds.length} odds updated`); }); eventSource.addEventListener('ev:detected', (e) => { const opps = JSON.parse(e.data); opps.forEach(opp => console.log(`+EV: ${opp.selection} at ${opp.ev_percentage}% EV`)); }); eventSource.addEventListener('heartbeat', () => { console.log('Connection alive'); }); eventSource.onerror = () => { console.log('Connection lost, auto-reconnecting...'); };

Node.js

import EventSource from 'eventsource'; const oddsMap = new Map(); const es = new EventSource( 'https://api.sharpapi.io/api/v1/stream?channel=odds&league=nba', { headers: { 'X-API-Key': 'YOUR_KEY' } } ); es.addEventListener('snapshot', (e) => { const { odds } = JSON.parse(e.data); for (const odd of odds) oddsMap.set(odd.id, odd); console.log(`Received ${odds.length} initial odds`); }); es.addEventListener('odds:update', (e) => { const { odds, book } = JSON.parse(e.data); // Merge compact deltas into local state for (const delta of odds) { const full = oddsMap.get(delta.id); if (full) Object.assign(full, delta); } console.log(`${book}: ${odds.length} odds updated`); });

Python

import sseclient import requests import json url = 'https://api.sharpapi.io/api/v1/stream' params = {'channel': 'all', 'league': 'nba'} headers = {'X-API-Key': 'YOUR_KEY'} odds_map: dict[str, dict] = {} response = requests.get(url, params=params, headers=headers, stream=True) client = sseclient.SSEClient(response) for event in client.events(): data = json.loads(event.data) if event.data else {} if event.event == 'connected': if data.get('reconnected'): odds_map.clear() print(f"Stream {data['stream_id']} connected") elif event.event == 'snapshot': for odd in data.get('odds', []): odds_map[odd['id']] = odd print(f"Snapshot: {data['count']} odds") elif event.event == 'odds:update': # Delta only has dynamic fields — merge by ID for delta in data.get('odds', []): existing = odds_map.get(delta['id']) if existing: existing.update(delta) print(f"{data['book']}: {data['count']} odds updated") elif event.event == 'ev:detected': for opp in data: print(f"+EV: {opp['selection']} at {opp['ev_percentage']}%")

Ereignistypen

EreignisBeschreibung
connectedStream aufgebaut, gibt Stream-ID, aktive Filter und Kanäle zurück
snapshot / opportunities_snapshotVollständiger Daten-Dump für Quoten/Opportunitäten (alle Felder)
snapshot:completeAlle initialen Daten wurden gesendet
odds:updateKompaktes Delta — nur dynamische Felder (id, odds_american, odds_decimal, odds_probability, line, is_live, odds_changed_at). Per id in den Snapshot-Zustand einfügen.
odds:removedQuoten von einem Sportsbook entfernt
ev:detectedNeue +EV-Opportunität gefunden
ev:expired+EV-Opportunität nicht mehr verfügbar
arb:detectedNeue Arbitrage-Opportunität gefunden
arb:expiredArbitrage-Opportunität nicht mehr verfügbar
middles:detectedNeue Middle-Opportunität gefunden (siehe Middles-Zusammenfassung für aggregierte Statistiken)
middles:expiredMiddle-Opportunität nicht mehr verfügbar
low_hold:detectedNeue Low-Hold-Opportunität gefunden
low_hold:expiredLow-Hold-Opportunität nicht mehr verfügbar
heartbeatKeep-Alive wird alle 30 Sekunden gesendet
errorBehebbarer Fehler (Verbindung bleibt offen)

SSE vs WebSocket

FunktionSSEWebSocket
ProtokollHTTP (einseitig)ws:// / wss:// (bidirektional)
EndpointGET /api/v1/streamwss://ws.sharpapi.io
Kanal-AbonnementsEinmal über Query-Parameter festgelegtJederzeit per subscribe-Nachricht aktualisierbar
Filter-UpdatesMit neuen Parametern wieder verbindensubscribe-Nachricht senden
WiederverbindungAutomatisch (Last-Event-ID)Manuell (mit Backoff)
Browser-UnterstützungNatives EventSourceNatives WebSocket
Am besten fürEinfache Konsumenten, SSRDynamische Filter, Zwei-Wege-Kommunikation

Beide Protokolle liefern dieselben Ereignistypen und Daten-Nutzlasten.

Vollständige API-Referenz

SDKs mit Streaming-Unterstützung

  • TypeScript SDK — Eingebauter SSE-Client mit typsicheren Event-Handlern
  • Python SDK — Handler-basierte und Iterator-basierte Streaming-Muster

Beispielprojekte

Last updated on