Cómo crear un bot de trading para Polymarket
La mayoría de los tutoriales de bots para Polymarket se basan en SDK que ya no existen. Este es el camino actual de principio a fin: qué instalar en 2026, cómo funciona realmente la autenticación, dónde están los huecos de datos y los modos de fallo que matan a los bots en la primera semana.
La mayoría de los tutoriales de bots para Polymarket están desactualizados
Polymarket ha pasado a SDK unificados: polymarket-client para Python y @polymarket/client para TypeScript. Reemplazan a py-clob-client, @polymarket/clob-client-v2, @polymarket/builder-relayer-client y @polymarket/builder-signing-sdk. Si una guía te dice que hagas pip install py-clob-client, o si tu asistente de IA genera ese import, está trabajando con material obsoleto. Todo lo que sigue usa los paquetes actuales.
Un bot de Polymarket tiene seis piezas: descubrir mercados, leer precios, decidir, colocar órdenes, gestionar posiciones y seguir vivo. Las dos primeras son fáciles, la cuarta es delicada y la sexta es donde mueren de verdad la mayoría de los bots. Esta guía recorre todo el camino con código verificado y es honesta sobre las partes que de verdad son difíciles.
Paso 0: decide qué opera tu bot
Vale la pena hacerlo antes de escribir una línea, porque determina todo lo demás. Los mercados de Polymarket se dividen en dos familias que casi no tienen nada en común:
| Mercados de eventos | Mercados cripto Up/Down | |
|---|---|---|
| Ejemplos | Elecciones, deportes, premios | btc-updown-5m, eth-updown-15m |
| Duración | De semanas a meses | De 5 minutos a 24 horas |
| Qué mueve el precio | Noticias, información, sentimiento | Microestructura y flujo de órdenes |
| La ventaja viene de | Estar mejor informado | Ser más rápido o poner mejores precios |
| Operaciones al día | Unas pocas | Cientos |
| Sensibilidad a la latencia | Baja | Alta |
Si vas a automatizar, casi seguro que te interesa la segunda familia: alta frecuencia, continua y lo bastante mecánica como para codificarla. Se explica a fondo en los mercados Up/Down explicados.
Paso 1: instala el SDK actual
Ambos SDK te dan una sola interfaz de cliente sobre todas las APIs de Polymarket, modelos tipados, paginación coherente y firma integrada, que es mucho trabajo delicado que no quieres volver a implementar.
pip install polymarket-client
# or: uv add polymarket-client / poetry add polymarket-clientHay cuatro clientes de Python, y elegir el correcto importa más de lo que parece:
| Cliente | Datos públicos | Trading | Tiempo real |
|---|---|---|---|
AsyncPublicClient | Sí | No | Sí |
AsyncSecureClient | Sí | Sí | Sí |
PublicClient | Sí | No | No |
SecureClient | Sí | Sí | No |
subscribe(). Los bots necesitan las variantes asíncronas; las síncronas son para scripts y notebooks.Empieza con el cliente público
Puedes construir y probar el descubrimiento, la lectura de precios, la generación de señales y todo tu pipeline de datos con AsyncPublicClient: sin claves, sin wallet, sin riesgo. Cambia a AsyncSecureClient solo cuando estés listo para colocar una orden. La mayoría de los bugs aparecen mucho antes.
Paso 2: encuentra mercados
El descubrimiento público de mercados no necesita ninguna credencial. El paginador del SDK es igual en todos los métodos de listado, así que este patrón se generaliza.
import asyncio
from polymarket import AsyncPublicClient
async def main() -> None:
async with AsyncPublicClient() as client:
pages = client.list_markets(closed=False, page_size=50)
# Iterate items directly when page boundaries do not matter.
async for market in pages.iter_items():
if "updown" in (market.slug or ""):
print(market.slug, market.condition_id)
asyncio.run(main())Hay dos cosas que interiorizar aquí. Primero, page.next_cursor es un cursor opaco: guárdalo tal cual si quieres reanudar un recorrido más tarde, y no intentes analizarlo ni construir uno. Segundo, /markets tiene el límite de tasa más estricto de toda la plataforma, 300 req / 10s, así que guarda en caché los metadatos de los mercados en lugar de volver a listarlos en un bucle caliente. Todas las cifras en la referencia de límites de tasa.
Paso 3: autentícate
Para operar hace falta una wallet. El SDK de Python construye el firmante a partir de una clave privada local:
import os
from polymarket import AsyncSecureClient
client = await AsyncSecureClient.create(
private_key=os.environ["POLYMARKET_PRIVATE_KEY"],
wallet=os.environ["POLYMARKET_WALLET_ADDRESS"],
)Por debajo, Polymarket usa dos capas de autenticación: L1 es una firma EIP-712 de la wallet que demuestra que controlas la dirección y te permite crear o derivar credenciales de API; L2 firma cada solicitud privada con esas credenciales usando HMAC-SHA256. El SDK gestiona ambas, que es el principal motivo para usarlo.
Los dos fallos de autenticación con los que te toparás
Credenciales incompletas: L2 necesita la key, el secret y la passphrase. Con dos de las tres se produce una solicitud bien formada con una firma que no se puede verificar. Desfase del reloj: la firma incluye una marca de tiempo, así que se rechaza un contenedor cuyo reloj va unos segundos desfasado. Ambos aparecen con el mismo y poco útil Unauthorized/Invalid api key. Explicación completa en la referencia de errores.
Gestión de claves
Esa clave privada puede mover fondos. Guárdala en variables de entorno o en un gestor de secretos: nunca en el código fuente, nunca en una imagen de contenedor, nunca en el repositorio que estás a punto de subir. Usa una wallet dedicada con solo lo que el bot puede permitirse perder, para que un bug quede limitado por el saldo y no por tu criterio a las 3 de la mañana.
Paso 4: obtén precios en tiempo real
El error de arquitectura más común en un primer bot es hacer polling de /book con un temporizador. Quema tu presupuesto de límite de tasa, añade latencia y escala mal. Suscríbete en su lugar: el SDK combina varios feeds en un único stream de eventos.
from polymarket.streams import MarketSpec
async with await client.subscribe([MarketSpec(token_ids=[token_id])]) as stream:
async for event in stream:
# MarketBookEvent | MarketPriceChangeEvent | MarketLastTradePriceEvent
# | MarketTickSizeChangeEvent | MarketBestBidAskEvent
# | NewMarketEvent | MarketResolvedEvent
handle(event)Si te conectas al WebSocket directamente en lugar de usar el SDK, debes enviar un PING cada 10 segundos o la conexión se corta, y necesitas custom_feature_enabled: true para recibir siquiera los eventos best_bid_ask, new_market y market_resolved. Eso y los patrones de reconexión se explican en la guía de WebSocket. Aparte, los precios de referencia pasaron a PolyBolt el 15 de septiembre de 2026: si tu bot recibe precios spot por streaming, consulta la guía de migración.
Paso 5: coloca una orden
Una orden de mercado es lo más sencillo que funciona, y amount está expresado en los pUSD que estás dispuesto a gastar, no en acciones:
market = await client.get_market(slug="<market-slug>")
token_id = market.outcomes.yes.token_id
assert token_id is not None
response = await client.place_market_order(
token_id=token_id,
side="BUY",
amount="10", # spend up to 10 pUSD
)
if not response.ok:
raise RuntimeError(response.message)
# Settlement is on-chain and asynchronous — this waits for it.
hashes = await client.wait_for_order_fill_settlement(response)En las órdenes límite en reposo, hay dos reglas que te morderán antes que nada. Los precios deben estar en la cuadrícula de ticks del mercado: llama a GET /tick-size para cada mercado en lugar de suponer 0.01, porque el tamaño del tick varía y puede reducirse a medida que el mercado madura. Y las órdenes por debajo del tamaño mínimo del mercado se rechazan directamente. Ambas vuelven como 400 con mensajes concretos, recogidos en la referencia de errores.
Un 200 en un lote no significa éxito
Cuando envías varias órdenes, los fallos de cada orden se devuelven dentro del array de la respuesta 200 como campos errorMsg individuales. Recorre el array y revisa cada entrada. Los bots que solo comprueban el estado HTTP creen en silencio que tienen posiciones que no tienen, un tipo de bug realmente peligroso.
Paso 6: averigua si la estrategia funciona
Todo lo anterior es fontanería, y la fontanería es la mitad fácil. La pregunta difícil es si tu estrategia gana dinero, y aquí es donde crear bots para Polymarket se aleja mucho de crear bots para cripto spot.
No hay testnet. Ni sandbox, ni API de demostración, ni endpoint de paper trading. Esas palabras no aparecen en ninguna parte de la documentación de Polymarket. Tu primera orden real es dinero real frente a contrapartes reales. Consulta ¿Polymarket tiene testnet? para ver las cuatro alternativas.
Y no hay libro de órdenes histórico. Cuando un mercado se resuelve, su libro devuelve 404. Conserva una serie de precios de aproximadamente un punto por minuto, y solo si la pides con un inicio y un fin explícitos:
TOK=<token_id_of_a_resolved_market>
START=<epoch seconds the window opened>
END=$((START + 300))
curl -s "https://clob.polymarket.com/book?token_id=$TOK"
# {"error":"No orderbook exists for the requested token id"} HTTP 404
curl -s "https://clob.polymarket.com/prices-history?market=$TOK&startTs=$START&endTs=$END&fidelity=1"
# about 6 points for a 5-minute market; interval=max returns [] for older onesAsí que no puedes hacer backtesting desde Polymarket. Necesitas snapshots puntuales que alguien haya grabado mientras los mercados estaban activos. Eso es lo que ofrece PolyTest para los mercados cripto Up/Down: 240M+ snapshots, 8 niveles de profundidad del libro por lado, marcas de tiempo por debajo del segundo y mercados resueltos conservados:
import os, requests
BASE = "https://api.polytest.io/api/v1"
H = {"X-API-Key": os.environ["POLYTEST_KEY"]}
markets = requests.get(f"{BASE}/markets",
params={"coin": "btc", "market_type": "5m", "limit": 50},
headers=H).json()["markets"]
snaps = requests.get(f"{BASE}/markets/{markets[0]['id']}/snapshots",
params={"include_orderbook": "true"},
headers=H).json()["snapshots"]
def simulate_fill(levels, qty):
"""Walk the ladder. Mid-price is not a price you can trade at."""
filled = cost = 0.0
for lvl in levels:
take = min(lvl["size"], qty - filled)
cost += take * lvl["price"]
filled += take
if filled >= qty:
break
return cost / filled if filled >= qty else None
print(simulate_fill(snaps[0]["orderbook"]["asks"], 500))El error que vuelve inútil un backtest
Si haces backtesting contra el precio medio, estás probando una identidad aritmética, no una estrategia. Los spreads Up/Down suelen ser de 2–5 centavos en un contrato que se liquida a $1, a menudo más que la ventaja que se dice tener. Recorre el libro y toma la ejecución que de verdad habrías obtenido. Este único cambio mata a la mayoría de las estrategias, que es exactamente lo que quieres que haga, barato y antes de financiarlas.
Paso 7: sobrevive al contacto con producción
Un bot que opera bien durante una hora y luego se queda colgado es peor que no tener bot. Estos son los modos de fallo que ocurren de verdad, más o menos en orden de frecuencia:
| Fallo | Lo que ves | Cómo gestionarlo |
|---|---|---|
| Limitación de tasa | La latencia sube, no hay errores | Cloudflare ralentiza en lugar de rechazar: vigila el p99, no la tasa de errores |
| Reinicio del motor de matching | 425 Too Early | Reintenta con backoff; no alertes por casos aislados |
| Exchange en pausa | 503 | Deja de abrir posiciones. Cancela si está permitido |
| Modo cancel-only | 503 en órdenes nuevas | La ruta de cancelación debe funcionar con independencia de la de entrada |
| Modo post-only | 503 + retry_after_seconds | Espera exactamente ese tiempo y reintenta |
| Desajuste de firmante | 400 error de firmante de la orden | Credenciales obsoletas de otra wallet: vuelve a derivarlas |
| Caída del WebSocket | Silencio | Que no haya datos no significa que no haya cambios: controla la antigüedad del último mensaje |
| Desfase del reloj | 401 en un bot que ayer funcionaba | Usa NTP; este es el que más tiempo hace perder |
El silencio es el estado peligroso
Un WebSocket caído no lanza una excepción: simplemente deja de entregar mensajes. Un bot con una posición abierta que no recibe actualizaciones creerá tan tranquilo que el mercado está congelado en el último precio que vio. Controla la antigüedad del último mensaje y trata el desfase como una condición de error, no como calma.
- Prueba la ruta de cancelación antes que la de entrada. No poder salir es mucho peor que no poder entrar.
- Limita la exposición en el código, no en tu cabeza. Un límite estricto de posición convierte un bug de lógica en una pérdida pequeña en lugar de una ilimitada.
- Construye un interruptor de emergencia y pruébalo de verdad. Un interruptor de emergencia sin probar es un comentario.
- Añade jitter al trabajo programado. Los workers que se despiertan en el segundo exacto crean un pico sincronizado muy por encima de tu tasa media.
- Registra cada solicitud y cada respuesta durante la primera semana. Las vas a necesitar y no podrás reconstruirlas después.
- Alerta por categorías, no por mensajes. Polymarket incluye IDs de órdenes y precios en los strings de error, así que alertar por el string literal es puro ruido.
Un orden de construcción realista
La secuencia que menos tiempo y dinero desperdicia:
- Integración de solo lectura, cliente público, sin claves. Demuestra el descubrimiento, el parsing, la paginación y el backoff. Un día, gratis.
- Haz backtesting de la estrategia con libros históricos y una simulación de ejecuciones honesta. La mayoría de las ideas mueren aquí. Ese es el objetivo.
- Paper trading en vivo durante al menos una semana: registra las órdenes que pretendías enviar en lugar de enviarlas. Demuestra la disponibilidad, las reconexiones y el timing.
- Sal en vivo con el tamaño mínimo, con un tope estricto de exposición y un interruptor de emergencia probado.
- Escala solo cuando las cifras en vivo coincidan con las del papel. Si divergen, tu modelo de ejecuciones estaba mal: vuelve al paso 2.
Los pasos 1, 3 y 4 puedes construirlos en unos días. El paso 2 necesita datos que Polymarket no conserva, y también es el paso que con más fiabilidad ahorra dinero. Empieza una prueba gratuita en PolyTest: suficiente para averiguar si tu idea sobrevive al spread.
Preguntas frecuentes
- ¿Cómo creo un bot de trading para Polymarket?
- Instala el SDK unificado actual: polymarket-client para Python o @polymarket/client para TypeScript. Usa AsyncPublicClient para descubrir mercados y leer precios sin credenciales, y después AsyncSecureClient con una clave privada para operar. Suscríbete al canal market del WebSocket en lugar de hacer polling de precios, coloca órdenes con place_market_order y gestiona las respuestas 425, 429 y 503 con backoff. Antes de salir en vivo, haz backtesting con snapshots históricos del libro de órdenes y simulación realista de ejecuciones, ya que Polymarket no tiene testnet ni conserva historial del libro de órdenes.
- ¿Qué SDK debo usar para un bot de Polymarket en 2026?
- Usa los SDK unificados: polymarket-client para Python o @polymarket/client para TypeScript. Reemplazan a los paquetes antiguos py-clob-client, @polymarket/clob-client-v2, @polymarket/builder-relayer-client y @polymarket/builder-signing-sdk. Hay un SDK unificado de Rust en desarrollo. La mayoría de los tutoriales y del código generado por IA siguen haciendo referencia a los paquetes obsoletos, así que revisa los imports antes de fiarte de un fragmento.
- ¿Puedo hacer paper trading en Polymarket antes de arriesgar dinero real?
- No a través de Polymarket: no hay testnet, sandbox ni API de demostración. Puedes construir tú mismo una capa de paper trading ejecutando el bucle de tu estrategia en vivo contra los datos de mercado de producción y registrando las órdenes que pretendías enviar, junto con el estado del libro en ese instante, en lugar de enviarlas. Eso demuestra que tu bot es sólido en operación, pero da por hechas las ejecuciones, así que no te enseñará nada sobre la posición en la cola ni el impacto en el mercado.
- ¿Cómo hago backtesting de un bot de trading de Polymarket?
- Necesitas snapshots históricos del libro de órdenes de un tercero, porque la API de Polymarket devuelve 404 para el libro de un mercado resuelto y solo conserva aproximadamente un punto por minuto del historial de precios. Descarga snapshots puntuales con la profundidad completa, reprodúcelos en orden cronológico sin mirar hacia delante y simula las ejecuciones recorriendo los niveles del libro en lugar de suponer el precio medio. Los spreads Up/Down de 2-5 centavos en un contrato de $1 suelen ser mayores que la ventaja que se dice tener, así que los backtests con el precio medio engañan.
- ¿Por qué mi bot de Polymarket recibe Unauthorized/Invalid api key?
- Casi siempre por una de dos cosas. O tu conjunto de credenciales está incompleto (la autenticación L2 necesita la clave de API, el secret y la passphrase juntos) o el reloj de tu sistema se ha desfasado, ya que la firma de la solicitud incluye una marca de tiempo y unos pocos segundos de desfase la invalidan. Con menos frecuencia, derivaste las credenciales con una wallet distinta de la que usas para operar.
- ¿Necesito un WebSocket para un bot de Polymarket o puedo hacer polling?
- Usa el WebSocket. Hacer polling de /book con un temporizador quema presupuesto de límite de tasa, añade latencia y escala mal. Suscríbete al canal market del CLOB para las actualizaciones públicas del libro y de precios, y al canal user para las actualizaciones de tus propias órdenes y operaciones. Si te conectas al WebSocket directamente en lugar de a través de un SDK, envía un PING cada 10 segundos para mantener viva la conexión.
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
La ventaja por retraso del spot en Polymarket es real. Y también tiene unos $100 de profundidad.
Compra el lado que el spot ya ha confirmado, antes de que Polymarket ajuste el precio. A diferencia de la mayoría de las estrategias que se anuncian, esta sobrevive al contacto con los datos, con un z-score de 15. El motivo por el que no ha hecho rico a todo el mundo está en el libro de órdenes.
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.
El SDK de Python de Polymarket en 2026 (y cómo dejar py-clob-client)
Si tu código todavía importa ClobClient desde py_clob_client, está construido sobre un paquete sustituido, igual que la mayor parte del código de Polymarket que te escribirá un asistente de IA. Este es el SDK actual y cómo pasarte a él.