Skip to Content
StreamingWebSocket

Streaming WebSocket

Actualizaciones de cuotas y oportunidades en tiempo real mediante WebSocket en wss://ws.sharpapi.io.

Para consultar la documentación completa de la API, incluidos todos los tipos de mensajes, esquemas y códigos de cierre, consulta la Referencia de la API WebSocket.

SSE frente a WebSocketPermalink for this section

SharpAPI ofrece dos protocolos de streaming. Ambos entregan los mismos datos a la misma velocidad.

SSEWebSocket
URLhttps://api.sharpapi.io/api/v1/streamwss://ws.sharpapi.io
DirecciónServidor → ClienteBidireccional
Filtros de actualizaciónRequiere reconexiónEnviar mensaje subscribe
ReconexiónAutomática (Last-Event-ID)Manual (implementar backoff)
Idóneo paraConsumidores sencillos, navegadoresAplicaciones interactivas, paneles

Elige SSE si configuras los filtros una vez y solo quieres que los datos fluyan. Elige WebSocket si necesitas cambiar los filtros sobre la marcha o prefieres un protocolo bidireccional.

Inicio rápidoPermalink for this section

1. ConectarPermalink for this section

Usa el parámetro channels para suscribirte únicamente a los datos que necesites:

// Only EV opportunities + odds — no middles, low_hold, or arbitrage const ws = new WebSocket( 'wss://ws.sharpapi.io?api_key=YOUR_KEY&channels=ev,odds&sport=basketball&sportsbook=draftkings&league=nba' );

Canales disponibles: ev, arbitrage, middles, low_hold, odds. Omite channels para recibir todo lo que admita tu nivel de suscripción.

Filtros disponibles: sport, sportsbook, league, market, event_id — todos separados por comas.

Filtros de umbral: min_ev (predeterminado 2.0), min_profit (predeterminado 0.5, se aplica solo a arbitrage, no a low-hold) — descartan oportunidades de bajo valor en el lado del servidor.

2. Gestionar mensajesPermalink for this section

ws.onmessage = (event) => { const msg = JSON.parse(event.data); switch (msg.type) { case 'connected': console.log(msg.message); // "Welcome to SharpAPI real-time odds stream" break; case 'opportunities_snapshot': if (msg.ev) console.log('EV:', msg.ev); // EV opportunity snapshot break; case 'initial': console.log('Odds:', msg.data); // Per-sportsbook odds snapshot break; case 'snapshot:complete': console.log('All initial data loaded'); // Safe to hide loading state break; case 'odds:update': console.log(msg.source, msg.data); // Incremental odds update break; case 'ev:detected': console.log('+EV:', msg.data); // New +EV opportunities (Pro+) break; } };

3. Mantener viva la conexiónPermalink for this section

setInterval(() => { if (ws.readyState === WebSocket.OPEN) { ws.send(JSON.stringify({ type: 'ping' })); } }, 25000);

4. Actualizar canales y filtros (sin reconectar)Permalink for this section

ws.send(JSON.stringify({ type: 'subscribe', channels: ['low_hold'], filters: { sports: ['football'], sportsbooks: ['fanduel', 'betmgm'], leagues: ['nfl'] } }));

Flujo de mensajesPermalink for this section

Al conectarte recibes los mensajes en este orden:

  1. connected — Mensaje de bienvenida con tu nivel de suscripción, características y canales activos
  2. subscribed — Confirmación de los canales y filtros activos
  3. opportunities_snapshot — Uno por cada canal de oportunidades suscrito (ev, arbitrage, middles, low_hold)
  4. initial — Snapshot de cuotas por sportsbook (solo si está suscrito el canal odds)
  5. snapshot:complete — Indica que se han enviado todos los datos iniciales

Fragmentación de snapshots y tamaño de frame: Los snapshots de gran tamaño se dividen en varios frames para evitar la contrapresión. Cada frame de snapshot está limitado a 256KB serializados; los snapshots de cuotas se dividen además por sportsbook, y los de oportunidades en hasta 300 elementos por frame. Espera al snapshot:complete antes de considerar que los datos iniciales se han cargado por completo. Si tu librería cliente impone un tamaño máximo de mensaje entrante, déjalo en 512KB o más — el valor por defecto de 1MB de Python websockets (max_size=2**20) es suficiente. Un cliente con un límite inferior a 256KB se cierra con 1009 (message too big) a mitad del snapshot y entrará en un bucle de reconexión sin llegar a recibir datos.

A partir de ahí, recibes actualizaciones incrementales de los canales suscritos:

  • odds:update — Han cambiado las cuotas de un sportsbook (requiere el canal odds)
  • odds:removed — Un sportsbook ha retirado cuotas (requiere el canal odds)
  • ev:detected / ev:expired — Oportunidades de +EV (requiere el canal ev)
  • arb:detected / arb:expired — Oportunidades de arbitraje (requiere el canal arbitrage)
  • middles:detected / middles:expired — Oportunidades de middle (requiere el canal middles)
  • low_hold:detected / low_hold:expired — Oportunidades de low-hold (requiere el canal low_hold)
  • heartbeat — Keepalive del servidor cada 30 segundos

ReconexiónPermalink for this section

A diferencia de SSE, WebSocket no se reconecta automáticamente. Implementa un backoff exponencial:

let reconnectDelay = 1000; let lastGlobalSeq = 0; ws.onmessage = (event) => { const msg = JSON.parse(event.data); if (msg.type === 'connected') lastGlobalSeq = msg.global_seq; if (msg.global_seq) lastGlobalSeq = msg.global_seq; }; ws.onclose = (event) => { if (event.code === 1000) return; // intentional close setTimeout(() => { reconnectDelay = Math.min(reconnectDelay * 2, 30000); // Use resume + from_seq for gap-free reconnection (2-min replay buffer) connect({ resume: true, from_seq: lastGlobalSeq }); }, reconnectDelay); };

Restablece reconnectDelay a 1000 cuando la conexión sea correcta.

El servidor mantiene un búfer de reproducción de 2 minutos. Pasa resume=true&from_seq=N al reconectar para omitir el snapshot completo y reproducir solo los eventos perdidos. Para interrupciones más largas, omite estos parámetros y obtendrás un snapshot completo. Consulta Reconexión con reproducción para más detalles.

Códigos de cierrePermalink for this section

CódigoSignificadoAcción
1000Cierre normalNo se requiere acción
1006Cierre anómalo (lado cliente)Caída de red — reconectar siempre
4001API key incorrecta o ausenteCorrige tu API key
4003Sin acceso a streamingAdquiere el complemento WebSocket
4029Demasiadas conexionesCierra primero las conexiones que no uses

El código 1006 está reservado por la RFC 6455 y el servidor nunca lo envía. Tu librería WebSocket lo genera localmente cuando la conexión TCP se cae sin un handshake de cierre (fallo de red, terminación del proceso). Reconecta siempre que lo veas — el ejemplo siguiente ya lo hace correctamente al omitir la reconexión solo en 1000.

Referencia completa de la APIPermalink for this section

Para acceder a la documentación completa, incluidos todos los esquemas de mensajes, la gestión de errores y los ejemplos en varios lenguajes, consulta la Referencia de la API WebSocket.

Last updated on