Monitorea Kalshi y Polymarket con Python
Kalshi y Polymarket publican catálogos y modelos de precios separados, cada uno con sus propios identificadores. Un monitor útil entre plataformas tiene que establecer que dos listados se refieren a la misma afirmación antes de poner sus precios en una misma fila. Dino se encarga de ese paso de coincidencia y devuelve un objeto Market con los precios de ambas plataformas, así el programa en Python puede concentrarse en filtrar y mostrar los datos.
Este tutorial construye un pequeño monitor de terminal con el paquete oficial dino-markets. Clasifica los mercados emparejados abiertos a partir del snapshot REST retrasado disponible en el plan Free. La sección final agrega el stream en tiempo real para recibir actualizaciones a medida que ocurren.
Instala el cliente y crea una clave
Crea una clave de API gratuita y guárdala en una variable de entorno. Luego instala el paquete de Python:
export DINO_API_KEY=sk_live_...
pip install dino-markets
El cliente lee DINO_API_KEY automáticamente. La primera solicitud obtiene el catálogo de Markets abiertos y en vivo, ordenado por la mayor diferencia de precio observada entre plataformas:
from dino_markets import Dino
client = Dino()
catalog = client.markets(
status="open,live",
sort="-spread_pts",
limit=25,
)
ranked = [
market
for market in catalog["markets"]
if market["spread_pts"] is not None
]
if not ranked:
raise SystemExit("No priced matched markets are available right now.")
print("as returned by the delayed REST snapshot")
for market in ranked:
print(
f'{market["spread_pts"]:>5.1f} pts '
f'{market["title"]:<42} '
f'{market["category"]}/{market["market_type"]}'
)
Los precios de REST se mantienen alrededor de dos minutos por detrás del precio en vivo en todos los planes. Eso hace que el resultado sea adecuado para explorar el catálogo y para investigación. También puede inicializar una vista local antes de que lleguen las actualizaciones del stream.
Muestra los precios de las dos plataformas en cada resultado
Cada Market mantiene la misma forma de outcomes[] en las categorías deportivas y no deportivas. Cada resultado lleva los precios de ambas plataformas más un campo cheaper. Un precio faltante es None, así que fíltralo explícitamente antes de calcular una diferencia:
def priced_outcomes(market):
return [
outcome
for outcome in market["outcomes"]
if outcome["kalshi"] is not None
and outcome["polymarket"] is not None
]
for market in ranked[:10]:
print(f'\n{market["title"]}')
for outcome in priced_outcomes(market):
gap = abs(outcome["kalshi"] - outcome["polymarket"]) * 100
print(
f' {outcome["name"]:<24} '
f'Kalshi {outcome["kalshi"]:.2f} '
f'Polymarket {outcome["polymarket"]:.2f} '
f'gap {gap:.1f} pts'
)
spread_pts es una observación sobre los resultados del Market. No significa que exista un arbitraje ejecutable. Las Opportunities confirmadas viven en el recurso separado client.find_arbitrage() y llevan patas seleccionadas, comisiones, tamaño y la vigencia del snapshot.
Revisa la resolución antes de usar una fila
La respuesta de la lista es liviana. Obtén un Market por su id estable cuando el monitor necesite los términos de cada plataforma y los riesgos de resolución:
selected = ranked[0]
detail = client.market(selected["id"])
print(detail["title"], detail["match"], detail["signal"])
for risk in detail.get("settlement", {}).get("risks", []):
print(risk["severity"], risk["event"], risk["note"])
El id es el identificador estable de Dino y es la clave correcta para las filas en caché. El título mostrado y los identificadores de cada plataforma pueden cambiar cuando un listado se vuelve a analizar. Vuelve a obtener el detalle cuando updated_at cambie, para que el monitor capte una identidad revisada o una nueva divulgación de resolución.
Agrega actualizaciones en tiempo real
Instala la dependencia opcional del stream y usa el helper de reconexión del SDK:
pip install "dino-markets[stream]"
import asyncio
from dino_markets import Dino, watch
client = Dino()
def on_publication(channel, frame):
if frame.get("type") != "price":
return
print(
channel,
frame["id"],
frame.get("spread_pts"),
frame.get("priced_at"),
)
asyncio.run(watch(client, on_publication))
El helper genera un ticket nuevo de corta duración en cada intento de conexión y recupera las publicaciones recientes después de una desconexión breve. Una clave Free recibe el canal sample curado. Todos los planes de pago reciben el stream completo de Market.
Mantén el bootstrap de REST en el programa incluso después de agregar las actualizaciones de WebSocket. Le da al monitor un snapshot inicial, mientras los frames del stream aplican los cambios de precio actuales a esos ids de Market en caché. La referencia de WebSocket documenta el comportamiento de recuperación, y la referencia del objeto Market cubre todos los campos usados aquí.
El monitor terminado lee datos emparejados y muestra las diferencias de precio. No coloca órdenes en ninguna de las dos plataformas. Son datos para desarrolladores, no asesoramiento financiero ni de trading. Crea una clave gratuita para ejecutar primero la versión de REST.
Más del blog
Kalshi + Polymarket MCP para Claude y Cursor
Conecta Claude o Cursor al servidor MCP de Kalshi y Polymarket de Dino, e inspecciona mercados emparejados con contexto de resolución.
Compara Kalshi y Polymarket de forma segura
Compara contratos de Kalshi y Polymarket con los riesgos de resolución y las diferencias de contrato asociadas a cada precio observado.
El capital institucional llegó a los mercados de predicción. Las materias primas son la prueba
ICE y Tradeweb respaldan a Polymarket y Kalshi. La liquidez de materias primas mostrará si la infraestructura institucional se convierte en flujo.