Todos los artículos
Referencia de la APIWebSocketsAPI de PolymarketBots de trading

WebSockets de Polymarket: datos en tiempo real que no se caen

Hacer polling del libro de órdenes es la forma más común de quemar presupuesto de límite de tasa sin ningún beneficio. Aquí están los cuatro streams, las opciones de suscripción que nadie documenta y el modo de fallo en el que tu bot recibe silencio y lo interpreta como calma.

10 min de lecturaActualizado el 24 de septiembre de 2026

Si tu bot hace polling de GET /book con un temporizador, esta página te ahorrará la mayor parte de tu presupuesto de límite de tasa y una buena parte de la latencia. Polymarket envía las actualizaciones del libro por WebSocket, y una suscripción te cuesta una conexión en lugar de miles de solicitudes.

La versión corta

Conéctate a wss://ws-subscriptions-clob.polymarket.com/ws/market, envía una suscripción con tus assets_ids y después envía un PING cada 10 segundos o te desconectarán. Pon custom_feature_enabled: true si quieres los eventos best_bid_ask, new_market o market_resolved: están desactivados por defecto y su ausencia se ve exactamente igual que un mercado tranquilo.

Los cuatro streams

StreamURLTransmiteAutenticación
Marketwss://ws-subscriptions-clob.polymarket.com/ws/marketActualizaciones públicas del libro, de precios y del ciclo de vidaNinguna
Userwss://ws-subscriptions-clob.polymarket.com/ws/userActualizaciones de tus órdenes y operacionesSí
RTDS (legado)wss://ws-live-data.polymarket.comComentarios; los precios de referencia pasaron a PolyBoltNinguna
PolyBoltwss://ws-live-v2.polymarket.com/wsPrecios de referencia cripto, de acciones y TWAPSí
Sportswss://sports-api.polymarket.com/wsEstado de los partidos en vivo y marcadoresNinguna

El canal User es el que la gente pasa por alto

Si tu bot hace polling de /data/orders para saber si su orden se ejecutó, estás gastando presupuesto de límite de tasa en información que el canal User te envía en el instante en que ocurre, y con menos latencia. Cualquier bot que coloque órdenes debería estar en este stream.

Los precios de referencia se movieron el 15 de septiembre de 2026

Polymarket lanzó PolyBolt y convirtió RTDS en legado para los precios de referencia. crypto_prices, crypto_prices_chainlink y equity_prices ahora están en wss://ws-live-v2.polymarket.com/ws, la fuente cambió de Binance/Chainlink a Pyth, los símbolos son btcusd en minúsculas en lugar de btcusdt o btc/usd, y ahora se requiere autenticación. El mapeo completo está en la guía de migración a PolyBolt. Todo lo demás de esta página (los canales market y user del CLOB) no se ve afectado.

Suscribirse al canal market

Conéctate y envía un mensaje JSON de suscripción. assets_ids recibe IDs de token (los mismos que obtienes de los metadatos del mercado) y type debe ser "market".

{
  "assets_ids": ["65818619657568813474341868652308942079804919287380422192892211131408793125422"],
  "type": "market",
  "initial_dump": true,
  "level": 2,
  "custom_feature_enabled": true
}
CampoObligatorioPor defectoQué hace
assets_idsSí—IDs de token a los que suscribirse
typeSí—Debe ser "market"
initial_dumpNotrueEnvía un snapshot completo del libro al suscribirte
levelNo2Nivel de suscripción: 1, 2 o 3
custom_feature_enabledNofalseActiva los eventos best_bid_ask, new_market y market_resolved

custom_feature_enabled es false por defecto

Esta es la trampa de la suscripción que le cuesta a la gente una tarde. Tres tipos de eventos (best_bid_ask, new_market y market_resolved) no se entregan salvo que los actives. No hay error ni aviso; simplemente nunca los recibes. Si estás esperando un evento market_resolved que nunca llega, este es el motivo.

Mantén initial_dump: true salvo que tengas un motivo concreto para no hacerlo. Sin él empiezas sin estado del libro y tienes que esperar a que las actualizaciones incrementales lo reconstruyan, lo que significa que tu bot arranca con una imagen incompleta.

Tipos de mensaje

Cada mensaje lleva un event_type. Ramifica sobre él de forma exhaustiva: un tipo no reconocido debe registrarse, no descartarse en silencio, porque así es como te enteras de que el protocolo cambió.

event_typeSignificadoHay que activarlo
bookSnapshot completo del libro de órdenesNo
price_changeActualización incremental de precio/nivelNo
last_trade_priceSe ejecutó una operaciónNo
tick_size_changeCambió la cuadrícula de ticks del mercadoNo
best_bid_askActualización del mejor nivel del libroSí
new_marketSe creó un mercadoSí
market_resolvedSe liquidó un mercadoSí

No ignores tick_size_change

El tamaño del tick es propio de cada mercado y puede reducirse a medida que el mercado madura. Si guardas en caché un tamaño de tick al arrancar y el mercado lo cambia, todas las órdenes límite posteriores se rechazan por infringir el tamaño mínimo de tick: un 400 que parece un bug en tu lógica de precios. Gestiona el evento y actualiza tu caché.

Mantener la conexión: PING cada 10 segundos

Este es el requisito que pilla a todo el mundo. El cliente debe enviar un PING cada 10 segundos; el servidor responde PONG. Si fallas el heartbeat, la conexión se corta.

Fíjate en la dirección: es un heartbeat del cliente. No estás esperando a que el servidor te haga ping. El keepalive integrado de una biblioteca WebSocket con otro intervalo no lo sustituye: envía tú mismo el PING a nivel de aplicación.

import asyncio, json, time
import websockets

URL = "wss://ws-subscriptions-clob.polymarket.com/ws/market"
STALE_AFTER = 30          # seconds without any message = treat as dead


async def stream(token_ids, on_event):
    backoff = 1
    while True:
        try:
            async with websockets.connect(URL) as ws:
                await ws.send(json.dumps({
                    "assets_ids": token_ids,
                    "type": "market",
                    "initial_dump": True,
                    "custom_feature_enabled": True,   # or lose 3 event types
                }))
                backoff = 1                            # reconnected cleanly
                last_msg = time.monotonic()

                async def heartbeat():
                    while True:
                        await asyncio.sleep(10)        # required cadence
                        await ws.send("PING")

                hb = asyncio.create_task(heartbeat())
                try:
                    while True:
                        # Silence is a failure mode, not a quiet market.
                        raw = await asyncio.wait_for(ws.recv(), timeout=STALE_AFTER)
                        last_msg = time.monotonic()
                        if raw == "PONG":
                            continue
                        for msg in json.loads(raw) if raw.startswith("[") else [json.loads(raw)]:
                            on_event(msg)
                finally:
                    hb.cancel()

        except Exception as exc:
            # Reconnect with capped exponential backoff + jitter.
            wait = min(backoff, 30) * (0.5 + 0.5 * asyncio.get_event_loop().time() % 1)
            print(f"ws down ({exc}); reconnecting in {wait:.1f}s")
            await asyncio.sleep(wait)
            backoff = min(backoff * 2, 30)

Usa el SDK salvo que tengas un motivo para no hacerlo

polymarket-client (Python) y @polymarket/client (TypeScript) implementan el heartbeat, la reconexión y el framing de mensajes, y combinan varios feeds en un único stream de eventos tipados. Hacerlo a mano solo compensa si necesitas un control que el SDK no expone. Ten en cuenta que las suscripciones son solo asíncronas: los clientes síncronos no implementan subscribe().

Cambiar suscripciones sin reconectar

Los mercados de cinco minutos vencen constantemente, así que un bot que sigue los “mercados BTC 5m actuales” tiene que cambiar su conjunto de suscripciones de forma continua. No tienes que cerrar la conexión para hacerlo: el canal market admite suscribirse y cancelar suscripciones sobre una conexión activa.

Esto importa más de lo que parece. Reconectar en cada rotación de mercado implica pagar una y otra vez el coste de establecer la conexión, volver a pedir los volcados iniciales y crear una ventana en la que no recibes nada justo cuando abre un mercado nuevo.

El modo de fallo que cuesta dinero

Un WebSocket caído no lanza una excepción. Deja de entregar mensajes. Para un bot ingenuo, “no hay actualizaciones” es indistinguible de “el mercado no se mueve”, así que un bot con una posición abierta se quedará indefinidamente con un precio desfasado, convencido de que nada ha cambiado.

  • Controla la antigüedad del último mensaje. Si no ha llegado nada en ~30 segundos en un mercado activo, estás desconectado, no en calma. El timeout de asyncio.wait_for de arriba hace exactamente eso.
  • Trata el desfase como una condición de error. Deja de cotizar, cierra posiciones si tus reglas de riesgo lo exigen y reconecta: no sigas operando con un libro congelado.
  • Espera entre reconexiones, con jitter. Un bucle de reconexión cerrado durante una caída es la forma de que te limiten la tasa además de estar desconectado, y una flota que reconecta al unísono lo empeora.
  • Resincroniza el estado después de reconectar. Te perdiste actualizaciones mientras no estabas. Toma el nuevo initial_dump como la verdad y descarta tu libro anterior, en lugar de fusionar actualizaciones incrementales con un snapshot desfasado.
  • Concilia las posiciones después de cualquier hueco. Si estuviste desconectado del canal User, puede que te perdieras una ejecución. Vuelve a leer las posiciones antes de actuar sobre un estado supuesto.

WebSockets y límites de tasa

Una pregunta frecuente, y la respuesta es el sentido de todo esto: una suscripción no consume presupuesto de límite de tasa por solicitud como el polling. Los límites documentados de Polymarket son límites HTTP por endpoint, y el streaming los esquiva casi por completo.

EnfoqueCoste de seguir 20 mercados durante una hora
Polling de /book cada segundo72,000 solicitudes frente a un presupuesto de 1,500 req/10s
Polling de /books (por lotes) cada segundo3,600 solicitudes frente a un presupuesto de 500 req/10s
Suscripción WebSocketUna conexión, más 360 heartbeats
Además, el polling te da una respuesta peor: ves el libro tal como estaba en tu último polling, no en el último cambio.

Seguirás haciendo llamadas HTTP (descubrimiento de mercados, tamaños de tick, colocación de órdenes, conciliación de posiciones), y esas siguen sujetas a los límites de tasa documentados. El streaming solo elimina la fuente de volumen de solicitudes más grande y menos útil.

La latencia es limitación disfrazada

Como la capa de Cloudflare limita retrasando en lugar de rechazando, un bot que hace polling por encima del límite no ve 429: ve cómo sus tiempos de respuesta suben sin hacer ruido. Si tus datos del libro han pasado de 40ms a 3 segundos, no estás sufriendo una caída; estás sufriendo tu propia tasa de solicitudes.

Lo que los streams no te darán

Un límite que conviene decir claramente, porque es lo que la gente intenta a continuación. Un WebSocket te da el libro desde el momento en que te suscribes. No puede darte el libro del martes pasado.

Polymarket no conserva ningún libro de órdenes histórico. Cuando un mercado se resuelve, su libro devuelve 404, y prices-history solo conserva aproximadamente un punto por minuto. Si quieres probar una estrategia con cómo se negociaron realmente los mercados, necesitas snapshots que alguien grabó en su momento. PolyTest lo hace para los mercados cripto Up/Down, con 8 niveles de profundidad por lado y mercados resueltos conservados. O pon en marcha tu propio recolector hoy, asume que empiezas sin historial y espera.

Preguntas frecuentes

¿Cuál es la URL del WebSocket de Polymarket?
El canal público de mercado es wss://ws-subscriptions-clob.polymarket.com/ws/market y el canal autenticado de usuario es wss://ws-subscriptions-clob.polymarket.com/ws/user. También hay otros dos streams: RTDS en wss://ws-live-data.polymarket.com para precios de referencia, comentarios y actividad de operaciones, y un feed de deportes en wss://sports-api.polymarket.com/ws.
¿Hay un límite de tasa en el WebSocket de Polymarket?
Una suscripción WebSocket no consume presupuesto de límite de tasa por solicitud como el polling HTTP: los límites documentados de Polymarket son límites HTTP por endpoint. El streaming es precisamente la forma recomendada de evitarlos. El requisito que sí obliga en una conexión es el heartbeat: envía un PING cada 10 segundos o la conexión se corta. Las llamadas HTTP que sigues haciendo para descubrimiento, tamaños de tick y colocación de órdenes siguen sujetas a los límites normales.
¿Cómo mantengo activa una conexión WebSocket de Polymarket?
Envía un mensaje PING cada 10 segundos; el servidor responde con PONG. Es un heartbeat a nivel de aplicación del lado del cliente, así que el keepalive integrado de una biblioteca WebSocket con otro intervalo no lo sustituye. Controla también la antigüedad del último mensaje recibido: una conexión caída deja de entregar datos sin generar un error, así que trata unos 30 segundos de silencio en un mercado activo como una desconexión y no como un mercado tranquilo.
¿Por qué no recibo los eventos best_bid_ask o market_resolved?
Esos eventos están desactivados por defecto. Pon custom_feature_enabled en true en tu mensaje de suscripción para activar best_bid_ask, new_market y market_resolved. No hay error ni aviso cuando falta el flag: los eventos simplemente nunca llegan, lo que es fácil de confundir con un mercado inactivo.
¿Mi bot de Polymarket debería usar WebSockets o hacer polling de la API REST?
Usa WebSockets para los datos en vivo del libro y de precios. Seguir 20 mercados haciendo polling de /book una vez por segundo cuesta 72,000 solicitudes por hora frente a un presupuesto de 1,500 req/10s, mientras que una suscripción cuesta una conexión más los heartbeats; además, el polling devuelve una respuesta más desfasada, ya que ves el libro tal como estaba en tu último polling y no en el último cambio. Deja REST para el descubrimiento de mercados, los tamaños de tick, la colocación de órdenes y la conciliación de posiciones.
¿Puedo cambiar los mercados a los que estoy suscrito sin reconectar?
Sí. El canal market admite suscribirse a activos y cancelar suscripciones sobre una conexión activa, lo que importa en mercados de vida corta como los contratos Up/Down de 5 minutos, que rotan constantemente. Reconectar en cada rotación supone pagar una y otra vez el coste de establecer la conexión y deja un hueco en la cobertura justo cuando abre un mercado nuevo.

Obtén los datos históricos que Polymarket no guarda

PolyTest registra los mercados cripto Up/Down de Polymarket mientras están activos: 240M+ snapshots con 8 niveles de profundidad del libro de órdenes, marcas de tiempo por debajo del segundo y mercados resueltos conservados. Empieza con una prueba gratuita de 3 días.

Sigue leyendo