Una estrategia comunitaria de Pine de nuestro corpus de paridad
llamada IES llevaba semanas sentada en paridad moderate frente a TradingView. Cuando
publicamos por última vez los números del corpus en
mayo, el corpus de paridad tenía 167 estrategias de referencia, 165 de ellas en paridad
estricta trade-por-trade contra TradingView. Desde entonces ha seguido creciendo. El corpus
ahora tiene 252 estrategias — 251 en paridad "excellent" (99,6%), una anomalía documentada,
cero fallos.
El número titular es la parte aburrida. Lo interesante es lo que apareció mientras llegábamos hasta ahí: tres comportamientos del broker de TradingView que no estábamos modelando, cada uno encontrado porque una estrategia real o sintética ejercitó una ruta de código que las 167 anteriores no tocaban. Este post repasa tres de ellos.
Dónde está el corpus
corpus/validation_report.md (2026-06-29)
Total probes: 252
Excellent: 251 (99.6%)
Anomaly: 1
Strong/Moderate/Weak/Minimal/Fail: 0
TV trades: 389,590
Engine trades: 389,688
Matched: 389,468El motor emite 98 trades más que TradingView en todo el corpus — un delta de 0,025% sobre 389.590 trades de referencia. Eso es el agregado; por estrategia, casi todo ese delta cae en la única anomalía de abajo, no en ruido repartido entre las otras 251.
Las seis pruebas más recientes son una categoría drawing, añadida cuando lanzamos un runtime
para leer objetos de dibujo de Pine (line.get_price, geometría de label/box) como datos en
tiempo de backtest, no solo como anotaciones del gráfico. Las estrategias que usan una línea
dibujada como estado computacional — una trendline anclada manualmente que actúa como nivel de
soporte dinámico, por ejemplo — necesitan que el motor siga sirviendo geometría para objetos
que el script ya borró, igual que hace TradingView. Las seis pasaron limpio.
La única anomalía, nombrada sin rodeos
No filtramos la única estrategia que no encaja. anomaly-equity-mirror-strategy-equity-01
está justo en el límite de equity 1× para admisión de margen. El emulador de broker de
TradingView es no-monótono exactamente en ese límite — admite algunas entradas con equity
insuficiente y rechaza algunas con equity suficiente, de forma inconsistente, barra a barra.
Nuestro motor es determinista: misma equity, misma decisión de admisión, siempre. Eso es
correcto según la semántica de margen documentada de Pine. También es, demostrablemente, lo
que TradingView no hace en ese límite concreto. Tendríamos que introducir nuestra propia
no-determinismo para igualarlo, así que no lo hacemos. El gap está documentado, no escondido,
y es el único de las 252.
Bug uno: la posición que TV habría liquidado a la fuerza
El broker de TradingView no espera a que la lógica de tu estrategia decida cuándo cerrar una
posición que reventó su requerimiento de margen — liquida directamente. Si la equity de una
posición apalancada o en corto cae lo suficiente como para que el margen requerido supere la
equity de la cuenta, TradingView fuerza el cierre de la posición en la siguiente barra, sin
importar qué condiciones de strategy.exit() se cumplan o no.
El motor no modelaba esto. Mantenía la posición y dejaba que la lógica propia de la estrategia la cerrara eventualmente — lo cual, en una estrategia sin un stop ajustado, podía significar decenas de barras con una posición que TradingView ya había liquidado. En estrategias del corpus con apalancamiento significativo, eso producía curvas de equity radicalmente distintas bajo estrés, incluso cuando la lógica de entrada y salida coincidía perfectamente en todo lo demás.
El fix añade liquidación forzada cuando la equity de la cuenta rompe el requerimiento de margen, calculando el precio de liquidación de la misma forma que el broker de TradingView, y luego cuantizando la cantidad liquidada al lot step del símbolo — TradingView no liquida lotes fraccionarios más pequeños de lo que el exchange permite, y ahora nosotros tampoco.
Esto afecta sobre todo a quien backtestea estrategias apalancadas o en corto sobre perpetuos. Si tu curva de equity se veía demasiado suave durante un drawdown, esta era, plausiblemente, la razón.
Bug dos: el chequeo de affordability que no sabía de FX
Las estrategias de Pine pueden declarar una moneda de cuenta distinta de la moneda de
cotización del símbolo — currency.INR operando un par en USDT, por ejemplo. Antes de
comprobar si puedes permitirte una orden, el broker de TradingView convierte el valor nocional
de la orden a tu moneda de cuenta usando el tipo de cambio vigente, y luego compara contra la
equity en esa misma moneda.
El gate de affordability del motor se saltaba la conversión. Comparaba el nocional en USDT
directamente contra la equity denominada en INR como si el tipo de cambio fuera 1:1 — lo que
hacía que una estrategia con currency.INR pareciera unas 83× más asequible de lo que
realmente era (dado que 1 USDT vale aproximadamente esa cantidad de rupias). En los scripts
afectados, eso prácticamente duplicaba el número de trades que el motor admitía y que el
broker de TradingView habría rechazado por no ser asequibles.
El fix aplica el tipo de cambio de la moneda de cuenta al margen requerido antes de que corra el chequeo de affordability, en el mismo punto del pipeline de órdenes donde lo aplica TradingView. Si estás backtesteando con una moneda de cuenta distinta del USD frente a un símbolo cotizado en USD o USDT, este era el bug que estaba inflando tu número de trades sin que te dieras cuenta.
Bug tres: el trailing stop que nunca se armaba
Este es el que más nos gustaría que un usuario hubiera detectado antes que nosotros, porque
falla en silencio. strategy.exit() admite dos formas de especificar un trailing stop:
trail_points, una distancia relativa a la entrada, y trail_price, un precio de activación
absoluto.
// armed correctly today; trail_price-only calls used to never arm at all
strategy.exit("TS", from_entry = "Long", trail_price = close * 1.05, trail_offset = 10)La condición de armado del motor solo comprobaba trail_points. Una salida trailing
especificada únicamente vía trail_price compilaba sin error, corría sin error, y nunca se
armaba — la posición simplemente se quedaba ahí sin ningún trailing stop activo, en silencio,
durante todo el backtest. Sin excepción, sin línea de log, sin trade. La estrategia parecía
protegida. No lo estaba.
Encontramos esto porque una prueba del corpus aísla específicamente la activación solo por
trail_price — exactamente el tipo de estrategia sintética y acotada para la que existe la
categoría validation, según el post sobre el desglose del corpus:
no rentable, no realista, construida para ejercitar una sola función de Pine en aislamiento,
de modo que un regresión así no pueda esconderse detrás de "los números generales se veían
bien".
El fix arma el trailing stop si hay presente trail_points o trail_price. Si alguna vez
escribiste una estrategia de Pine usando trail_price y la curva de equity se veía
sospechosamente como si no hubiera ningún trailing stop — no lo había, en ninguna versión del
motor anterior a esta.
Por qué esto es el verdadero sentido de tener un corpus
Ninguno de estos tres bugs se encontró por code review. Se encontraron porque una estrategia con la forma correcta corrió por el motor y produjo un número que no coincidía con el de TradingView. Esa es toda la tesis detrás de mantener 167 estrategias, luego 252, y contando como un corpus versionado y held-out en vez de un puñado de smoke tests: bugs que no cambian el recuento de trades ni el precio de entrada pueden seguir cambiando el número que de verdad importa — cuánto ganó o perdió la estrategia — y la única forma de detectarlos es seguir corriendo más formas de estrategia contra el mismo diff frente a la misma ground truth.
Seguiremos añadiendo pruebas a medida que encontremos gaps, y seguiremos publicando los números — los buenos y la única anomalía — tal como estén.
Por dónde seguir
- Explora la galería — las 252 estrategias, con tier de paridad y número de trades en cada card.
- Lee cómo encontramos un bug de margen parecido — un bug distinto, un límite distinto, el mismo método: aislar, diffear, arreglar.
- Prueba la API de codegen — transpila una estrategia de Pine y backtestéala con tu propio OHLCV desde Claude, Cursor o cualquier cliente MCP.
- Consigue acceso anticipado — tier gratis, 100 transpilaciones al mes.
