1. Introducción al Compilador v6
Pine Script v6 es la última evolución del lenguaje de programación propietario de TradingView. Está diseñado para crear indicadores personalizados y estrategias de backtesting robustas que se ejecutan directamente en la nube. A diferencia de las versiones previas, la versión 6 introduce un analizador de tipos más estricto y un motor de cálculo optimizado que reduce significativamente el tiempo de procesamiento de datos históricos.
Para iniciar cualquier script compatible con el estándar actual, debes incluir la directiva de versión en la línea superior del editor:
//@version=6
indicator("Mi Indicador Gueta", overlay=true)
plot(close, color=color.teal) 2. Tipos de Datos y Estructura Sintáctica
El sistema de tipado de Pine Script v6 se divide en formas fundamentales y formas de serie. Las variables pueden ser declaradas de forma explícita para evitar errores de compilación o dejar que el compilador infiera el tipo dinámicamente.
Es un estándar fundamental de buenas prácticas declarar de forma estricta las variables numéricas y los booleanos cuando se construyen reglas de riesgo complejas:
| Tipo de Dato | Sintaxis v6 | Uso Cuantitativo |
|---|---|---|
| int | `int length = 14` | Definir ventanas de cálculo o periodos de medias móviles. |
| float | `float stopLoss = 1.5` | Cálculo de niveles de precios exactos y gestión de riesgo. |
| bool | `bool buySignal = true` | Evaluación de condiciones lógicas para disparar órdenes. |
| color | `color fill = color.rgb(29, 158, 117)` | Formato visual del gráfico según las alertas de volumen. |
3. Regla Práctica: Media Móvil Simple
Las funciones integradas en la versión 6 de Pine Script requieren que las variables que alimentan sus parámetros estén correctamente formateadas. El siguiente script calcula un filtro de media móvil simple (SMA) utilizando una validación condicional estricta.
//@version=6
indicator("Filtro Cuantitativo Gueta", overlay=true)
// Configuración de parámetros
int period = input.int(20, title="Periodo de Cálculo")
float source = input.source(close, title="Fuente de Precio")
// Cálculo de la Media Móvil
float maValue = ta.sma(source, period)
// Regla de coloración
color maColor = source > maValue ? color.green : color.red
plot(maValue, title="Media Gueta", color=maColor, linewidth=2) En este ejemplo, la constante period define la ventana del cálculo del promedio móvil. Mantener un riesgo controlado del 1.5% por operación complementa este tipo de análisis técnico.
4. Tutorial Avanzado: Salida Dinámica por ATR (Average True Range)
Una de las grandes ventajas de Pine Script v6 es su capacidad para calcular stop-loss adaptativos basados en volatilidad real. El indicador ATR mide la fuerza del movimiento del mercado. A continuación, te mostramos cómo programar un stop trailing dinámico:
//@version=6
indicator("Stop Trailing ATR Gueta", overlay=true)
int atrLength = input.int(14, title="Periodo ATR")
float atrMultiplier = input.float(2.0, title="Multiplicador ATR")
// Cálculo de ATR
float atrValue = ta.atr(atrLength)
float stopPrice = close - (atrValue * atrMultiplier)
// Asegurar que el trailing stop solo suba en una posición de compra
var float trailingStop = na
trailingStop := not na(trailingStop[1]) ? math.max(stopPrice, trailingStop[1]) : stopPrice
plot(trailingStop, title="Trailing Stop ATR", color=color.orange, style=plot.style_linebr) Este bloque de código define un stop que se ajusta automáticamente a medida que el precio se mueve a favor de la operación, reduciendo las pérdidas potenciales ante giros rápidos del mercado financiero.
5. Backtesting de Alta Precisión y Mitigación de Sesgos (Look-ahead Bias)
El "Look-ahead Bias" (o sesgo de anticipación) es el error más recurrente y destructivo en el desarrollo de trading cuantitativo. Ocurre cuando un script utiliza información del futuro para tomar decisiones de trading. En TradingView, esto genera curvas de rendimiento perfectas en el simulador que fracasan rotundamente al ejecutarse en tiempo real.
5.1 Evitando la Fuga de Datos (Data Leakage)
Para evitar por completo este sesgo y asegurar que el backtest represente la operativa real, se deben aplicar dos reglas obligatorias en la arquitectura de request.security(): el uso de la referencia desplazada [1] en la serie solicitada y la desactivación explícita mediante lookahead=barmerge.lookahead_off.
//@version=6
strategy("Gueta Quant - Antídoto Look-Ahead Bias", overlay=true, initial_capital=10000000, default_qty_type=strategy.percent_of_equity, default_qty_value=10)
string timeframeSuperior = input.timeframe("D", title="Temporalidad Superior MTF")
bool usarFiltroCorrecto = input.bool(true, title="Activar Filtro Correcto (Sin Sesgo)")
float cierreDiarioSesgado = request.security(syminfo.tickerid, timeframeSuperior, close, lookahead=barmerge.lookahead_on)
float cierreDiarioCorrecto = request.security(syminfo.tickerid, timeframeSuperior, close[1], lookahead=barmerge.lookahead_off)
float precioReferencia = usarFiltroCorrecto ? cierreDiarioCorrecto : cierreDiarioSesgado
float maLocal = ta.sma(close, 20)
bool señalLargo = close > maLocal and close > precioReferencia
bool salidaLargo = close < maLocal
if señalLargo and (strategy.position_size == 0)
strategy.entry("Largo MTF", strategy.long)
if strategy.position_size > 0 and salidaLargo
strategy.close("Largo MTF")
plot(maLocal, color=color.blue)
plot(precioReferencia, color=usarFiltroCorrecto ? color.green : color.red, linewidth=2) 6. Depuración Profesional mediante el Espacio de Nombres log
Uno de los mayores desafíos para los desarrolladores era la falta de un entorno de depuración interactivo en tiempo de ejecución. Anteriormente, dependíamos de pintar etiquetas (label.new) en el gráfico para inspeccionar variables, lo cual ralentizaba la plataforma.
Pine Script v6 soluciona esto introduciendo el espacio de nombres log, el cual permite escribir mensajes directamente en la consola "Pine Logs" del editor mediante log.info(message), log.warning(message) y log.error(message).
//@version=6
indicator("Gueta Quant - Filtro de Volatilidad v6", overlay=false)
int lengthInput = input.int(20, title="Período de Volatilidad")
float thresholdInput = input.float(1.5, title="Umbral de Desviación")
bool enableLogs = input.bool(true, title="Habilitar Depuración en Consola")
float priceClose = close
float basis = ta.sma(priceClose, lengthInput)
float dev = ta.stdev(priceClose, lengthInput)
float thresholdValue = float(thresholdInput)
float volumeSeries = volume
float volumeAverage = ta.sma(volumeSeries, lengthInput)
bool isHighVolume = volumeSeries > volumeAverage
bool isVolatilityAlert = (dev > (basis * thresholdValue / 100.0)) and isHighVolume
if enableLogs and (bar_index > last_bar_index - 100)
string logMessage = "Barra #" + str.tostring(bar_index) + " | Cierre: " + str.tostring(priceClose) + " | Desviación: " + str.tostring(dev)
if isVolatilityAlert
log.info(logMessage)
else if dev > (basis * thresholdValue / 100.0)
log.warning("Volatilidad alta sin volumen en barra " + str.tostring(bar_index))
color dynamicColor = isVolatilityAlert ? color.rgb(34, 196, 138) : color.rgb(239, 68, 68)
plot(dev, title="Desviación Estándar Filtrada", color=dynamicColor, style=plot.style_columns) 7. Estructuras de Datos Avanzadas (Arrays y Maps)
El análisis cuantitativo profesional exige modelar la información de forma compleja. En Pine Script v6, las estructuras de datos avanzadas permiten simular carteras, gestionar historiales de órdenes y procesar perfiles de volumen de forma óptima sin recurrir a variables sueltas y dispersas.
Los arrays son colecciones ordenadas del mismo tipo de datos, ideales para almacenar registros dinámicos de transacciones. Por otro lado, los mapas (map) representan una adición fundamental para almacenar datos relacionales indexados por claves únicas (como nombres de activos, niveles de precio o identificadores de órdenes).
//@version=6
indicator("Gueta Quant - Gestor de Riesgo Multiactivo", overlay=true)
type Posicion
string activo
float precioEntrada
float tamañoLote
float stopLoss
int barraApertura
float capitalCuenta = input.float(100000.0, title="Capital Total de la Cuenta (USD)")
float riesgoPorcentaje = input.float(1.0, title="Riesgo Máximo por Operación (%)")
var Posicion[] historialPosiciones = array.new()
var map riesgoActivosMap = map.new()
if barstate.isfirst
map.put(riesgoActivosMap, "BCOLOMBIA", 0.015)
map.put(riesgoActivosMap, "ECOPETROL", 0.020)
map.put(riesgoActivosMap, "COLCAP", 0.010)
float fastMA = ta.sma(close, 9)
float slowMA = ta.sma(close, 21)
bool señalCompra = ta.crossover(fastMA, slowMA)
float atrValue = ta.atr(14)
float stopLossCalculado = close - (atrValue * 2.0)
string tickerLimpio = syminfo.ticker
float riesgoEspecifico = map.contains(riesgoActivosMap, tickerLimpio) ? map.get(riesgoActivosMap, tickerLimpio) : (riesgoPorcentaje / 100.0)
float distanciaPrecio = close - stopLossCalculado
float tamañoPosicionCalculado = 0.0
if distanciaPrecio > 0
tamañoPosicionCalculado := (capitalCuenta * riesgoEspecifico) / distanciaPrecio
if señalCompra and tamañoPosicionCalculado > 0
Posicion nuevaOp = Posicion.new(tickerLimpio, close, tamañoPosicionCalculado, stopLossCalculado, bar_index)
array.push(historialPosiciones, nuevaOp)
if barstate.islast and array.size(historialPosiciones) > 0
Posicion ultimaPos = array.get(historialPosiciones, array.size(historialPosiciones) - 1)
label.new(x=bar_index, y=high, text="Último Trade: " + ultimaPos.activo + "\nLote: " + str.tostring(ultimaPos.tamañoLote, "#.##"), color=color.black, textcolor=color.white) 8. Ejecución en Tiempo Real y Conectividad con APIs (Webhooks)
La transmisión de alertas automatizadas mediante Webhooks dinámicos es el estándar para conectar TradingView con brokers externos. El motor de TradingView ejecuta el script en la nube y envía solicitudes HTTP POST en formato JSON a microservicios intermediarios que traducen la petición a protocolos de corretaje (API REST o FIX).
Es fundamental dar formato a los parámetros dinámicos (como el tamaño de la posición o el precio de ejecución) controlando el número de decimales mediante str.tostring() para evitar errores de deserialización en las APIs de destino.
//@version=6
strategy("Sistema de Conectividad API - Gueta Quant", overlay=true, initial_capital=10000)
string api_token = input.string("GUETA_SECURE_AUTH_TOKEN_XYZ", title="Token de Autenticación API")
string broker_route = input.string("LITEFINANCE_CO", title="Ruta del Broker")
bool signal_buy = ta.crossover(ta.sma(close, 10), ta.sma(close, 20))
bool signal_sell = ta.crossunder(ta.sma(close, 10), ta.sma(close, 20))
fn_build_json(string action, float order_qty, float current_price) =>
"{" +
"\"auth_token\": \"" + api_token + "\"," +
"\"symbol\": \"" + syminfo.ticker + "\"," +
"\"action\": \"" + action + "\"," +
"\"quantity\": " + str.tostring(order_qty, "#.##") + "," +
"\"execution_price\": " + str.tostring(current_price, "#.##") +
"}"
float size_to_execute = (strategy.equity * 0.02) / close
if (signal_buy)
string buy_json = fn_build_json("BUY", size_to_execute, close)
strategy.entry("Long", strategy.long, alert_message=buy_json)
if (signal_sell)
string sell_json = fn_build_json("SELL", size_to_execute, close)
strategy.entry("Short", strategy.short, alert_message=sell_json) 9. Gestión Cuantitativa de Riesgo (Drawdown y Dimensionamiento)
El éxito de un sistema algorítmico depende de la consistencia matemática de su riesgo. El tamaño de la posición debe calcularse en base al capital disponible y a la volatilidad medida por el ATR. Adicionalmente, implementar un interruptor de parada de emergencia (Breaker Switch) basado en el drawdown máximo de la cuenta protege el portafolio de pérdidas severas de capital.
//@version=6
strategy("Estrategia Cuantitativa de Riesgo Controlado - Gueta Quant", overlay=true, initial_capital=100000, default_qty_type=strategy.cash)
float risk_percent = input.float(1.5, title="Riesgo por Operación (%)") / 100.0
float max_drawdown_pct = input.float(5.0, title="Límite de Drawdown Portafolio (%)") / 100.0
int atr_period = input.int(14, title="Periodo ATR")
float atr_multiplier = input.float(2.0, title="Multiplicador ATR")
float current_atr = ta.atr(atr_period)
var float max_equity = strategy.initial_capital
max_equity := math.max(max_equity, strategy.equity)
float current_drawdown = (max_equity - strategy.equity) / max_equity
bool system_halted = current_drawdown >= max_drawdown_pct
bool entry_long_cond = ta.crossover(ta.ema(close, 20), ta.ema(close, 50))
bool entry_short_cond = ta.crossunder(ta.ema(close, 20), ta.ema(close, 50))
float stop_distance_ticks = current_atr * atr_multiplier
float target_risk_usd = strategy.equity * risk_percent
float calculated_size = target_risk_usd / stop_distance_ticks
if (not system_halted)
if (entry_long_cond and strategy.position_size == 0)
strategy.entry("Largo Cuant", strategy.long, qty=calculated_size)
strategy.exit("Salida Largo", "Largo Cuant", stop=close - stop_distance_ticks)
if (entry_short_cond and strategy.position_size == 0)
strategy.entry("Corto Cuant", strategy.short, qty=calculated_size)
strategy.exit("Salida Corto", "Corto Cuant", stop=close + stop_distance_ticks)
else
if (strategy.position_size != 0)
strategy.close_all(comment="CIRCUITO DE RIESGO ACTIVADO: LIQUIDACIÓN")
plot(max_equity, title="Máximo Histórico de Equity", color=color.green, style=plot.style_stepline)
plot(strategy.equity, title="Equidad Actual", color=color.blue) 10. Errores Comunes de Compilación en la Versión 6
El compilador v6 de TradingView es mucho más estricto con los tipos de datos y la declaración de variables. Te presentamos los errores más recurrentes y sus soluciones directas:
| Error del Compilador | Causa Probable | Corrección Sugerida |
|---|---|---|
| `Cannot assign value to immutable variable` | Intentar reasignar un valor a una variable declarada con `=` en lugar de `:=`. | Usa el operador de reasignación `:=` para modificar variables mutables. |
| `Cannot call ta.* functions in conditional blocks` | Las funciones técnicas (como `ta.ema`) deben ejecutarse en cada barra y no dentro de un `if`. | Calcula la función técnica fuera del bloque condicional y evalúa el resultado dentro del `if`. |
| `Type mismatch: expected float, found int` | Intentar sumar o asignar tipos diferentes sin conversión explícita. | Aplica conversión explícita usando la función `float()` o `int()`. |
Preguntas Frecuentes
¿Cuáles son las principales mejoras de Pine Script v6?
Pine Script v6 optimiza la velocidad de cálculo en TradingView, introduce un tipado más estricto para evitar errores en tiempo de ejecución y mejora la eficiencia en el backtesting de estrategias cuantitativas complejas.
¿Cómo se declara la versión en el compilador?
Se declara en la primera línea del script utilizando la directiva //@version=6 para indicar al compilador de TradingView que use las reglas sintácticas más recientes.
¿Cuáles son las ventajas clave de Pine Script v6 frente a la versión 5 en trading cuantitativo?
Pine Script v6 introduce mejoras significativas en el rendimiento de ejecución, un manejo más eficiente de colecciones y matrices dinámicas, y una precisión mejorada en el motor de backtesting histórico. Esto permite procesar estructuras de datos complejas como tipos definidos por el usuario (UDTs) con menor consumo de recursos.
¿Cómo se gestiona el desbordamiento de memoria al usar colecciones dinámicas en Pine Script v6?
Para evitar desbordamientos, se recomienda limitar el tamaño máximo de arrays y mapas mediante pre-asignación de memoria y limpieza activa de datos históricos innecesarios. En v6, el uso de las funciones integradas de recolección de basura optimiza este comportamiento de forma nativa.
¿Cómo implementar una arquitectura de control de riesgo multi-activo en Pine Script v6?
Se puede estructurar solicitando datos de tickers secundarios con la función request.security() combinada con tipos definidos por el usuario (UDTs). Esto centraliza la lógica de exposición al riesgo y el tamaño de la posición dentro de un único script maestro.
¿Por qué mi script antiguo arroja error en v6?
Muchas funciones de ta.* de las versiones v4 o v5 han cambiado de nombre o requieren conversión explícita de tipos. Te recomendamos migrar tus scripts antiguos paso a paso utilizando la herramienta integrada de TradingView o reescribiendo la sintaxis basándote en la especificación v6.
¿El uso de Pine Script v6 tiene costo en TradingView?
No. Escribir y compilar código en el editor de Pine Script es completamente gratuito. Solo se requieren planes de pago si necesitas ejecutar alertas automatizadas de alta frecuencia o si buscas cargar más de 3 indicadores simultáneos en un mismo gráfico.