Una métrica bonita es la mentira más cara que existe. Esta es la historia del «ganador» que no existía y del error de una sola línea que casi me arruina el experimento.
Episodio 3. Antes: por qué el copy-trading es una trampa.

Para copiar a los buenos, primero hay que encontrarlos. Así que le pedí a mi IA un script que analizara carteras de Polymarket y me dijera quién gana.
El script escupía win-rates preciosos. 65%. 70%. Traders que, según mis datos, acertaban dos de cada tres veces. Me froté las manos y empecé a copiarlos.
Y perdía. Una y otra vez.
La pista: un perfil rojo, un dato verde
Un día copié a un trader que mi análisis marcaba como sólido. Fui a su perfil público de Polymarket por curiosidad.
−23.718 dólares en un solo día.
Mi script decía que ese tío tenía un 65% de aciertos. Su perfil decía que estaba sangrando. Una de las dos cosas era mentira. Y como el perfil lo pinta la propia Polymarket, la mentirosa era mi herramienta.
Llevaba días tomando decisiones con dinero real a partir de un número que mi propio código se estaba inventando. Y me enteré de pura casualidad.
El bug: cómo la API te oculta a los perdedores
La API de posiciones de Polymarket permite ordenar resultados. Yo pedía las posiciones ordenadas por valor actual, descendente (sortBy=CURRENT DESC), y me quedaba con las primeras N.
Parece inofensivo. No lo es.
Ordenar por valor actual descendente pone arriba las posiciones que valen mucho ahora (las ganadoras, con precio cerca de 1) y manda al fondo las que valen casi nada (las perdedoras, con precio cerca de 0). Como yo solo leía las primeras N, estaba leyendo casi exclusivamente las ganadoras.
El resultado: un win-rate fantasma. No medía la habilidad del trader. Medía mi propio sesgo de muestreo.
# Lo que hacía (MAL): solo veo la cima del iceberg
positions = get_positions(wallet, sortBy="CURRENT", direction="DESC", limit=200)
win_rate = wins(positions) / len(positions) # inflado: faltan las perdedoras
# El arreglo: combinar ambos extremos y deduplicar
top = get_positions(wallet, sortBy="CURRENT", direction="DESC", limit=500)
bottom = get_positions(wallet, sortBy="CURRENT", direction="ASC", limit=500)
all_positions = dedupe(top + bottom) # ahora veo ganadoras Y perdedoras
El segundo error, más sutil: contar vs. pesar
Cuando por fin vi todas las posiciones, apareció otro matiz. Un trader podía tener un win-rate por conteo positivo (gana más veces de las que pierde) y aun así estar en rojo en dólares.
¿Cómo? Ganando muchas apuestas pequeñas y perdiendo unas pocas enormes.
El número de aciertos no paga las facturas. Las pagan los dólares. Y un buen win-rate puede convivir alegremente con una cuenta en números rojos.
A partir de ahí cambié toda la métrica: dejé de contar aciertos y empecé a sumar PnL ponderado por dólares. Solo así un «ganador» era de verdad un ganador.
El precio del error
Tres días. Tres días persiguiendo traders que mi propio código había coronado por error. Tres días copiando a gente que perdía, convencido de que ganaban.
Lo más doloroso no fue el dinero. Fue darme cuenta de que el fallo no estaba en Polymarket, ni en el mercado, ni en la IA. Estaba en una decisión de muestreo que tomé sin pensar y que nunca verifiqué contra la realidad (el perfil público) hasta que el azar me obligó.
Lo que aprendí
- Toda métrica derivada de una API es una hipótesis, no un hecho. Verifícala contra una fuente independiente (aquí: el perfil que pinta la propia plataforma) antes de apostar un céntimo.
- El orden y los límites de una consulta pueden sesgar tus datos. «Las primeras N ordenadas por X» casi nunca es una muestra representativa.
- Cuenta dólares, no eventos. El win-rate por conteo es una de las métricas más engañosas de las finanzas de retail.
- Cuando un dato te conviene, dúdalo más, no menos. Aquel 65% me gustaba demasiado como para cuestionarlo. Ese fue el verdadero bug.
Con la herramienta por fin honesta, pude separar a los ganadores reales de los espejismos. Y entonces probé dos ideas que no dependían de copiar a nadie: arbitraje puro y un bot basado en el tiempo. Las dos eran preciosas. Las dos estaban muertas antes de nacer. Ese es el próximo episodio.
Episodio 4: «Dos ideas preciosas que el mercado ya había matado».
👈 Anterior: La trampa del copy-trading · 👉 Siguiente: Dos ideas que el mercado ya había matado
Puedes leer esta entrada en inglés en: https://medium.com/@lluisabg/the-bug-that-cost-us-three-days-cab67df9c8a5
3 comentarios en «El bug que nos costó tres días»