polymarket-bot

Bot de paper trading para mercados de predicción de Polymarket: estrategia bayesiana sobre el precio de mercado como prior, señales externas en log-odds, gates de riesgo en cascada y un motor de replay determinista para calibración offline. API FastAPI + dashboard React. Desplegado en k3s vía GitOps (Gitea Actions → registry → ArgoCD), con PostgreSQL, secrets por Infisical y observabilidad completa (Grafana, uptime-kuma, Telegram).

📦 Estado del proyecto: ARCHIVADO (julio 2026). El 26 de mayo de 2026 la DGOJ ordenó el bloqueo cautelar de Polymarket y Kalshi en España por operar sin licencia de juego (CoinDesk). Con el bloqueo a nivel de ISP la fuente de datos primaria desaparece, así que el proyecto se jubila de forma ordenada: datos respaldados y verificados, resultados documentados en el informe final, e infraestructura apagada vía GitOps. El cierre es parte de la historia del proyecto, no un abandono — los módulos centrales son agnósticos de la fuente y el pivote natural es Manifold Markets (API abierta, play-money, sin fricción regulatoria).

El problema y la solución

Los mercados de predicción publican probabilidades implícitas en el precio. La hipótesis: en mercados de bajo volumen hay ineficiencias detectables combinando el precio con señales externas (noticias, sentimiento cripto, mercados espejo en otras plataformas). El bot la pone a prueba sin arriesgar dinero, con la disciplina de un sistema real:

  1. Prior desde el precio de Polymarket (mid del order book CLOB).
  2. Ajuste bayesiano en log-odds con señales independientes: GNews (con presupuesto de 5 consultas/día y guardrail que limita el ajuste a prior±0,25), Fear&Greed, momentum BTC, dominancia BTC, y Manifold Markets como señal cruzada (en modo observacional tras detectarse un bug de inversión — auditado en 165k filas).
  3. Gates en cascada antes de operar: prior extremo (<0,08 / >0,92), edge bruto mínimo por régimen de volatilidad, edge neto positivo tras comisión (2%) y spread, confianza ≥0,55, conflicto de familias, guard de reentrada.
  4. Agrupación por familias de mercados: mercados hermanos del mismo evento (candidatos de una misma elección, umbrales de un mismo precio) comparten family_key; solo se mantiene la posición de mayor edge para no apilar la misma apuesta con dos nombres.
  5. Sizing por Kelly fraccionado con techo por posición sobre un bankroll simulado de $10.000.

Resultado honesto en 81 días: 12 trades (n estadísticamente irrelevante, y el informe lo subraya), realized +$247,78, y — más interesante — ~223.000 evaluaciones archivadas con su decisión reproducible, porque el sistema prefirió no operar antes que operar sin ventaja medible. Detalle completo: docs/informe-final.md.

Arquitectura

flowchart LR
    subgraph ext["Fuentes externas"]
        PM["Polymarket<br/>CLOB + Gamma API"]
        GN["GNews"]
        MF["Manifold Markets"]
        CG["CoinGecko /<br/>alternative.me"]
    end

    subgraph k3s["k3s · namespace polymarket-bot"]
        BOT["bot (ciclo ~64s)<br/>estrategia bayesiana + gates"]
        PG[("PostgreSQL 16<br/>trades · signals · replay")]
        API["api (FastAPI :8000)"]
        DASH["dashboard (React/nginx)"]
        CJ1["CronJob metrics-retention 00:10"]
        CJ2["CronJob outcomes-joiner 00:30"]
    end

    subgraph obs["Observabilidad"]
        GRAF["Grafana"]
        UK["uptime-kuma"]
        TG["Telegram"]
    end

    PM --> BOT
    GN --> BOT
    MF --> BOT
    CG --> BOT
    BOT --> PG
    PG --> API
    API --> DASH
    API --> GRAF
    UK --> DASH
    BOT --> TG
    PM --> CJ2
    CJ2 --> PG
    CJ1 --> PG

    subgraph ci["GitOps"]
        GA["Gitea Actions"] --> REG["registry"] --> ARGO["ArgoCD<br/>prune + selfHeal"]
    end
    ARGO -.-> k3s

Decisiones de diseño

  • Paper trading por diseño, no como demo: el bot exigía ≥10 mercados resueltos y ≥30 días antes de considerarse promocionable a dinero real, y reportaba n/a (insufficient_sample) en vez de métricas infladas.
  • Todo skip es un dato: cada evaluación archiva prior, estimación, edge bruto/neto, descomposición por feature en log-odds y el gate exacto que la bloqueó (~55k filas/día en signals).
  • Replay determinista (julio 2026): inyección de reloj + re-ejecución de ciclos archivados con 22.697/22.697 decisiones idénticas; joiner diario de resoluciones UMA para calibrar sobre todas las evaluaciones, no solo los trades.
  • Los errores se cierran y se documentan: el bug de inversión de Manifold y los conflictos de familia cerraron 5 posiciones en abril; la señal pasó a observacional-only con auditoría completa en vez de eliminarse.
  • GitOps estricto: nunca kubectl para cambios persistentes (ArgoCD con selfHeal revierte cualquier parche manual); secrets fuera de git vía Infisical operator; smoke test PostSync con notificación a Telegram.

Componentes

Componente Código Imagen CMD
bot bot/ polymarket-bot python3 -m bot.main
api api/ (+ bot/ como librería) polymarket-bot-api uvicorn api.main:app
dashboard dashboard/ polymarket-bot-dashboard nginx estático

Dashboard (hasta el apagado): https://polymarket.chemavx.xyz

Stack

Python 3 (asyncio) · FastAPI · React + Vite · PostgreSQL 16 · k3s · ArgoCD · Gitea Actions + BuildKit · Infisical (secrets) · Grafana + Prometheus · uptime-kuma · Telegram Bot API.

CI/CD

⚠️ Decomisión: el trigger automático push:main se desactivó en la Fase 1 del archivado; el workflow queda solo bajo workflow_dispatch manual.

.gitea/workflows/ci.yml construye solo las imágenes cuyos ficheros cambiaron en el push (diff contra github.event.before):

  • bot/, api/, requirements.txt → bot + api (ambas imágenes copian las mismas fuentes Python; solo cambia el CMD)
  • Dockerfile → bot · Dockerfile.api → api · dashboard/ → dashboard
  • .gitea/workflows/ci.yml, primer push o force-push → todas (fallback seguro)
  • tests/, docs → ninguna (la CI no construye ni despliega nada)

Las imágenes se tagean con ${GITHUB_SHA::8}; el CI actualiza solo los deployments reconstruidos en k8s-manifests/polymarket-bot/ y ArgoCD sincroniza vía webhook en segundos.

Tests

python3 -m pytest tests/ -q

Datos y backup

Base de datos respaldada y verificada (2026-07-06): pg_dump -Fc + exports CSV.gz de las tablas de señales y auditoría, con checksums y restore de prueba (recuentos idénticos 11/11 tablas). Ubicación: almacenamiento de backups del clúster con sync offsite. El dump final se toma en la fase de apagado.

Documentación

  • Informe final de paper trading — resultados, pipeline de datos y estado de la BD al cierre.
  • docs/pivot-manifold.md — notas de diseño del posible pivote (Fase 5, pendiente).
S
Description
Polymarket trading bot
Readme
2.6 MiB
2026-07-06 07:40:44 +00:00
Languages
Python 95.8%
JavaScript 2.9%
CSS 1.1%
Dockerfile 0.1%