//╔════════════════════════════════════════════════════════════════════════╗ //║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║ //║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║ //║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║ //║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║ //║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║ //║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║ //╚═══════ Algorithms that observe ════ Signals that speak ════════════════╝ // //+------------------------------------------------------------------+ //| Archivo : CoralTrendIndicator.mq4 | //| Origen : Coral Trend Indicator [LazyBear] - TradingView | //| URL ref. : tradingview.com/script/qyUwc2Al | //| | //| El Coral Trend Indicator es matematicamente identico al | //| T3 Moving Average de Tim Tillson (TASC, Enero 1998). | //| Consiste en 6 EMAs en cascada combinadas via coeficientes | //| de expansion binomial de tercer grado: | //| bfr = -cd^3 * e6 + c3*e5 + c4*e4 + c5*e3 | //| donde c3 = 3(cd^2 + cd^3), c4 = -3(2cd^2 + cd + cd^3), | //| c5 = 1 + 3cd + 3cd^2 + cd^3. | //| | //| Herencia: Sistema THV (Traders Harmonic Volatility) de | //| JanusTrader/CobraForex en ForexFactory. LazyBear porto | //| el indicador MT4 a Pine Script en Enero 2015. | //| | //| Implementacion MQL4: | //| - No existe DRAW_COLOR_LINE en MQL4. Se usan 3 buffers | //| separados (Up/Down/Neutral) para simular la linea coloreada. | //| - Indexacion nativa inversa: indice 0 = barra mas reciente. | //| - El bucle itera de indice alto a bajo (pasado a presente). | //| - Las EMAs se inicializan con el valor puntual de la serie | //| fuente en seedIdx, evitando contaminacion por ceros. | //+------------------------------------------------------------------+ #property copyright "Exobeacon Labs" #property link "https://www.exobeacon.com/" #property version "1.0" #property description "Coral Trend Indicator [LazyBear] v1.0" #property description "T3 Moving Average (Tillson, 1998) with trend coloring." #property description "6 cascaded EMAs + binomial polynomial combination." #property description "Ported from TradingView Pine Script (LazyBear)." #property description " " #property description "-------------------------------------------" #property description "mql5.com/en/users/ulisescalb" #property description "github.com/Exobeacon-Labs" #property strict //+------------------------------------------------------------------+ //| Propiedades del indicador | //+------------------------------------------------------------------+ // --- Ventana: sobre el grafico de precios --- #property indicator_chart_window // --- Total de buffers: 3 visibles (Up/Down/Neutral) + 6 internos (i1-i6) = 9 --- #property indicator_buffers 9 // --- Plot 0: Linea alcista (verde) --- #property indicator_color1 clrLime #property indicator_width1 3 #property indicator_style1 STYLE_SOLID // --- Plot 1: Linea bajista (rojo) --- #property indicator_color2 clrRed #property indicator_width2 3 #property indicator_style2 STYLE_SOLID // --- Plot 2: Linea neutral (azul) --- #property indicator_color3 clrDodgerBlue #property indicator_width3 3 #property indicator_style3 STYLE_SOLID //+------------------------------------------------------------------+ //| Parametros de entrada | //| Nota: MQL4 no soporta 'input group'. Usamos comentarios. | //+------------------------------------------------------------------+ //--- Coral Algorithm --- extern int InpSmoothPeriod = 21; // Smoothing Period extern double InpConstantD = 0.4; // Constant D (Volume Factor) extern int InpAppliedPrice = PRICE_CLOSE; // Applied Price (0=Close,1=Open,2=High,3=Low,4=Median,5=Typical,6=Weighted) //--- Display --- extern int InpLineWidth = 3; // Trend Line Width (1-5) extern color InpColorUp = clrLime; // Uptrend Color extern color InpColorDown = clrRed; // Downtrend Color extern color InpColorNeutral = clrDodgerBlue; // Neutral Color //--- Alerts --- extern bool InpEnableAlerts = false; // Enable Alert System extern bool InpAlertPopup = true; // Alert: Popup extern bool InpAlertSound = false; // Alert: Sound extern bool InpAlertPush = false; // Alert: Push Notification extern bool InpAlertEmail = false; // Alert: Email //+------------------------------------------------------------------+ //| Buffers del indicador | //+------------------------------------------------------------------+ // --- Buffers visibles: 3 lineas coloreadas (simulan DRAW_COLOR_LINE) --- // Cada buffer contiene el valor Coral donde corresponde, EMPTY_VALUE donde no. double g_bufferUp[]; // Buffer 0: Segmentos de tendencia alcista double g_bufferDown[]; // Buffer 1: Segmentos de tendencia bajista double g_bufferNeutral[]; // Buffer 2: Segmentos neutrales // --- Buffers internos: 6 EMAs en cascada --- double g_i1[]; // Buffer 3: EMA cascada nivel 1 (sobre precio) double g_i2[]; // Buffer 4: EMA cascada nivel 2 (sobre i1) double g_i3[]; // Buffer 5: EMA cascada nivel 3 (sobre i2) double g_i4[]; // Buffer 6: EMA cascada nivel 4 (sobre i3) double g_i5[]; // Buffer 7: EMA cascada nivel 5 (sobre i4) double g_i6[]; // Buffer 8: EMA cascada nivel 6 (sobre i5) //+------------------------------------------------------------------+ //| Variables globales | //+------------------------------------------------------------------+ // --- Coeficientes del filtro (calculados una vez en OnInit) --- double g_c1 = 0.0; // Factor de suavizado alpha = 2/(di+1) double g_c2 = 0.0; // Complemento (1 - alpha) double g_c3 = 0.0; // Coeficiente para i5: 3*(cd^2 + cd^3) double g_c4 = 0.0; // Coeficiente para i4: -3*(2*cd^2 + cd + cd^3) double g_c5 = 0.0; // Coeficiente para i3: 1 + 3*cd + 3*cd^2 + cd^3 double g_cd3 = 0.0; // Coeficiente para i6: cd^3 // --- Control de alertas --- datetime g_lastAlertTime = 0; // Tiempo de la ultima alerta enviada // --- Barras minimas para estabilizacion del filtro --- int g_drawBegin = 0; //+------------------------------------------------------------------+ //| OnInit - Inicializacion del indicador | //+------------------------------------------------------------------+ int OnInit() { // --- Validacion de parametros de entrada --- if(InpSmoothPeriod < 1) { Print("ERROR: Smoothing Period must be >= 1. Current: ", InpSmoothPeriod); return(INIT_PARAMETERS_INCORRECT); } if(InpConstantD < 0.0 || InpConstantD > 2.0) { Print("ERROR: Constant D must be between 0.0 and 2.0. Current: ", DoubleToStr(InpConstantD, 4)); return(INIT_PARAMETERS_INCORRECT); } if(InpLineWidth < 1 || InpLineWidth > 5) { Print("ERROR: Line Width must be between 1 and 5. Current: ", InpLineWidth); return(INIT_PARAMETERS_INCORRECT); } // --- Asignacion de buffers --- // Buffers visibles: 3 lineas coloreadas SetIndexBuffer(0, g_bufferUp); SetIndexBuffer(1, g_bufferDown); SetIndexBuffer(2, g_bufferNeutral); // Buffers internos: 6 EMAs en cascada SetIndexBuffer(3, g_i1); SetIndexBuffer(4, g_i2); SetIndexBuffer(5, g_i3); SetIndexBuffer(6, g_i4); SetIndexBuffer(7, g_i5); SetIndexBuffer(8, g_i6); // --- Estilos de los buffers visibles --- SetIndexStyle(0, DRAW_LINE, STYLE_SOLID, InpLineWidth, InpColorUp); SetIndexStyle(1, DRAW_LINE, STYLE_SOLID, InpLineWidth, InpColorDown); SetIndexStyle(2, DRAW_LINE, STYLE_SOLID, InpLineWidth, InpColorNeutral); // --- CRITICO: Ocultar buffers internos con DRAW_NONE --- // En MQL4, SetIndexBuffer asigna DRAW_LINE por defecto a TODOS los buffers. // Sin DRAW_NONE, los buffers internos se dibujan como lineas negras, // distorsionando la escala del grafico. SetIndexStyle(3, DRAW_NONE); SetIndexStyle(4, DRAW_NONE); SetIndexStyle(5, DRAW_NONE); SetIndexStyle(6, DRAW_NONE); SetIndexStyle(7, DRAW_NONE); SetIndexStyle(8, DRAW_NONE); // --- Valor vacio para buffers visibles --- SetIndexEmptyValue(0, EMPTY_VALUE); SetIndexEmptyValue(1, EMPTY_VALUE); SetIndexEmptyValue(2, EMPTY_VALUE); // --- Etiquetas --- SetIndexLabel(0, "Coral Up"); SetIndexLabel(1, "Coral Down"); SetIndexLabel(2, "Coral Neutral"); SetIndexLabel(3, NULL); // Ocultar en DataWindow SetIndexLabel(4, NULL); SetIndexLabel(5, NULL); SetIndexLabel(6, NULL); SetIndexLabel(7, NULL); SetIndexLabel(8, NULL); // --- PLOT_DRAW_BEGIN: evitar basura visual en las primeras barras --- g_drawBegin = InpSmoothPeriod * 3; SetIndexDrawBegin(0, g_drawBegin); SetIndexDrawBegin(1, g_drawBegin); SetIndexDrawBegin(2, g_drawBegin); // --- Nombre corto del indicador --- IndicatorShortName(StringFormat("Coral Trend(%d, %.2f)", InpSmoothPeriod, InpConstantD)); // --- Digitos del indicador (misma precision que el precio) --- IndicatorDigits((int)MarketInfo(_Symbol, MODE_DIGITS)); // --- Pre-calculo de coeficientes del filtro Coral/T3 --- // Paso 1: Factor de suavizado alpha derivado del periodo // di = (sm - 1) / 2 + 1 => Para sm=21: di=11 // alpha = 2 / (di + 1) => Para sm=21: alpha = 2/12 = 0.16667 const double di = (InpSmoothPeriod - 1.0) / 2.0 + 1.0; g_c1 = 2.0 / (di + 1.0); g_c2 = 1.0 - g_c1; // Paso 2: Coeficientes polinomiales derivados de Constant D // Expansion binomial de T3 = GD(GD(GD(src))): // T3 = (1+v)^3 * e3 - 3v(1+v)^2 * e4 + 3v^2(1+v) * e5 - v^3 * e6 const double cd = InpConstantD; const double cd2 = cd * cd; g_cd3 = cd * cd2; // cd^3 g_c3 = 3.0 * (cd2 + g_cd3); // 3*(cd^2 + cd^3) = 3*v^2*(1+v) g_c4 = -3.0 * (2.0 * cd2 + cd + g_cd3); // -3*(2cd^2 + cd + cd^3) = -3*v*(1+v)^2 g_c5 = 3.0 * cd + 1.0 + g_cd3 + 3.0 * cd2; // 1 + 3cd + 3cd^2 + cd^3 = (1+v)^3 // --- Verificacion: la suma de coeficientes debe ser 1.0 (ganancia unitaria) --- const double coeffSum = -g_cd3 + g_c3 + g_c4 + g_c5; if(MathAbs(coeffSum - 1.0) > 1e-10) { PrintFormat("WARNING: Coefficient sum = %.15f (expected 1.0)", coeffSum); } // --- Inicializacion de variable de control de alertas --- g_lastAlertTime = 0; return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| OnDeinit - Limpieza al remover el indicador | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // --- Limpiar comentario del chart si hubiera --- Comment(""); } //+------------------------------------------------------------------+ //| GetPrice - Obtener el precio segun el tipo configurado | //| En MQL4 usamos los arrays predefinidos Open/High/Low/Close | //| con indexacion inversa (indice 0 = barra mas reciente). | //+------------------------------------------------------------------+ double GetPrice(const int shift) { switch(InpAppliedPrice) { case PRICE_OPEN: return(Open[shift]); case PRICE_HIGH: return(High[shift]); case PRICE_LOW: return(Low[shift]); case PRICE_CLOSE: return(Close[shift]); case PRICE_MEDIAN: return((High[shift] + Low[shift]) / 2.0); case PRICE_TYPICAL: return((High[shift] + Low[shift] + Close[shift]) / 3.0); case PRICE_WEIGHTED: return((High[shift] + Low[shift] + Close[shift] + Close[shift]) / 4.0); default: return(Close[shift]); } } //+------------------------------------------------------------------+ //| GetPeriodString - Convertir periodo a string legible | //| MQL4 no tiene EnumToString(Period()), necesitamos helper manual. | //+------------------------------------------------------------------+ string GetPeriodString() { switch(Period()) { case PERIOD_M1: return("M1"); case PERIOD_M5: return("M5"); case PERIOD_M15: return("M15"); case PERIOD_M30: return("M30"); case PERIOD_H1: return("H1"); case PERIOD_H4: return("H4"); case PERIOD_D1: return("D1"); case PERIOD_W1: return("W1"); case PERIOD_MN1: return("MN"); default: return("M" + IntegerToString(Period())); } } //+------------------------------------------------------------------+ //| OnCalculate - Calculo principal del indicador | //| | //| NOTA IMPORTANTE sobre indexacion MQL4: | //| - Indice 0 = barra mas reciente (actual) | //| - Indice Bars-1 = barra mas antigua | //| - El bucle itera de indice alto a bajo (pasado a presente) | //| - Para EMAs recursivas: ema[i] depende de ema[i+1] | //| (el valor "anterior" tiene indice mayor en MQL4) | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { // --- Verificar minimo de barras disponibles --- if(rates_total < 2) return(0); // --- Determinar barra de inicio del calculo --- // En MQL4 con indexacion inversa: // - Primera ejecucion: empezar desde la barra mas antigua (rates_total - 1) // - Ejecuciones subsiguientes: recalcular desde donde nos quedamos int limit; if(prev_calculated <= 0) { // Primera ejecucion: calcular todo el historial limit = rates_total - 1; } else { // Ejecuciones subsiguientes: recalcular ultima barra + nueva limit = rates_total - prev_calculated + 1; // Asegurar que no excedemos el rango if(limit > rates_total - 1) limit = rates_total - 1; } // --- Indice de semilla: la barra mas antigua del historial --- const int seedIdx = rates_total - 1; // --- Inicializacion de semilla para EMAs en cascada --- // CRITICO: Usar el valor puntual de la serie fuente como semilla. // NO usar SMA como semilla de EMAs de orden superior, ya que los // buffers se inicializan a 0.0 y contaminarian el calculo. if(prev_calculated <= 0) { const double seedPrice = GetPrice(seedIdx); // Inicializar la barra mas antigua con el precio como semilla g_i1[seedIdx] = seedPrice; g_i2[seedIdx] = seedPrice; g_i3[seedIdx] = seedPrice; g_i4[seedIdx] = seedPrice; g_i5[seedIdx] = seedPrice; g_i6[seedIdx] = seedPrice; // Valor Coral en la semilla const double bfrSeed = -g_cd3 * g_i6[seedIdx] + g_c3 * g_i5[seedIdx] + g_c4 * g_i4[seedIdx] + g_c5 * g_i3[seedIdx]; g_bufferUp[seedIdx] = EMPTY_VALUE; g_bufferDown[seedIdx] = EMPTY_VALUE; g_bufferNeutral[seedIdx] = bfrSeed; // Neutral en la primera barra // Ajustar limit para no reprocesar la semilla limit = seedIdx - 1; } // --- Bucle principal: de pasado a presente (indice alto a bajo) --- for(int i = limit; i >= 0; i--) { // --- Obtener el precio de entrada para esta barra --- const double src = GetPrice(i); // === ETAPA 1: Seis EMAs en cascada === // En MQL4 con indexacion inversa: ema[i] = alpha * input + (1-alpha) * ema[i+1] // (i+1 es la barra anterior en el tiempo, ya calculada) g_i1[i] = g_c1 * src + g_c2 * g_i1[i + 1]; g_i2[i] = g_c1 * g_i1[i] + g_c2 * g_i2[i + 1]; g_i3[i] = g_c1 * g_i2[i] + g_c2 * g_i3[i + 1]; g_i4[i] = g_c1 * g_i3[i] + g_c2 * g_i4[i + 1]; g_i5[i] = g_c1 * g_i4[i] + g_c2 * g_i5[i + 1]; g_i6[i] = g_c1 * g_i5[i] + g_c2 * g_i6[i + 1]; // === ETAPA 2: Combinacion polinomial Coral/T3 === // bfr = -cd^3 * i6 + c3 * i5 + c4 * i4 + c5 * i3 const double bfr = -g_cd3 * g_i6[i] + g_c3 * g_i5[i] + g_c4 * g_i4[i] + g_c5 * g_i3[i]; // Valor previo del Coral (barra anterior en el tiempo = i+1) const double bfrPrev = -g_cd3 * g_i6[i + 1] + g_c3 * g_i5[i + 1] + g_c4 * g_i4[i + 1] + g_c5 * g_i3[i + 1]; // === ETAPA 3: Asignar color por pendiente === // Inicializar todos los buffers visibles como vacios g_bufferUp[i] = EMPTY_VALUE; g_bufferDown[i] = EMPTY_VALUE; g_bufferNeutral[i] = EMPTY_VALUE; // === ETAPA 4: Determinar tendencia y asignar al buffer correspondiente === // Para continuidad visual, tambien asignamos el valor al buffer activo // en la barra anterior (i+1), creando segmentos conectados. if(bfr > bfrPrev) { // Tendencia alcista g_bufferUp[i] = bfr; // Conectar con la barra anterior para continuidad de la linea if(g_bufferUp[i + 1] == EMPTY_VALUE) g_bufferUp[i + 1] = bfrPrev; } else if(bfr < bfrPrev) { // Tendencia bajista g_bufferDown[i] = bfr; // Conectar con la barra anterior para continuidad de la linea if(g_bufferDown[i + 1] == EMPTY_VALUE) g_bufferDown[i + 1] = bfrPrev; } else { // Neutral (sin cambio) g_bufferNeutral[i] = bfr; // Conectar con la barra anterior para continuidad de la linea if(g_bufferNeutral[i + 1] == EMPTY_VALUE) g_bufferNeutral[i + 1] = bfrPrev; } } // --- Sistema de alertas: evaluar en la ultima vela cerrada (indice 1) --- if(InpEnableAlerts && rates_total >= 3) { ProcessAlerts(); } return(rates_total); } //+------------------------------------------------------------------+ //| ProcessAlerts - Evaluar y enviar alertas de cambio de tendencia | //| Se evalua sobre la vela cerrada (indice 1) comparada con la | //| vela anterior (indice 2) para evitar repintado. | //+------------------------------------------------------------------+ void ProcessAlerts() { // --- Evitar alertas duplicadas: una alerta por vela --- if(Time[1] <= g_lastAlertTime) return; // --- Determinar tendencia actual (indice 1) y anterior (indice 2) --- // Reconstruir el valor Coral para los indices 1 y 2 para determinar estado const int trendCurr = GetTrendState(1); const int trendPrev = GetTrendState(2); // --- Detectar cambio de tendencia --- if(trendCurr == trendPrev) return; // Sin cambio, no alertar // --- Construir mensaje de alerta --- string direction = ""; if(trendCurr == 0) direction = "BULLISH"; // Cambio a tendencia alcista else if(trendCurr == 1) direction = "BEARISH"; // Cambio a tendencia bajista else direction = "NEUTRAL"; // Cambio a neutral // Prefijo con nombre del indicador, simbolo y timeframe const string prefix = StringFormat("Coral Trend | %s %s | ", _Symbol, GetPeriodString()); const string message = prefix + "Trend changed to " + direction; // --- Registrar tiempo de alerta para evitar duplicados --- g_lastAlertTime = Time[1]; // --- Enviar por los canales configurados --- if(InpAlertPopup) Alert(message); if(InpAlertSound) PlaySound("alert.wav"); if(InpAlertPush) SendNotification(message); if(InpAlertEmail) SendMail("Coral Trend Alert", message); } //+------------------------------------------------------------------+ //| GetTrendState - Determinar el estado de tendencia en una barra | //| Retorna: 0 = alcista, 1 = bajista, 2 = neutral | //| Se evalua revisando cual buffer visible tiene valor en esa barra.| //+------------------------------------------------------------------+ int GetTrendState(const int shift) { if(g_bufferUp[shift] != EMPTY_VALUE && g_bufferUp[shift] != 0.0) return(0); // Alcista if(g_bufferDown[shift] != EMPTY_VALUE && g_bufferDown[shift] != 0.0) return(1); // Bajista return(2); // Neutral } //+------------------------------------------------------------------+ //| | //| ================================================================ | //| REFERENCIA: CODIGO PINE SCRIPT ORIGINAL | //| ================================================================ | //| | //| Autor : LazyBear | //| Script : Coral Trend Indicator [LazyBear] | //| URL : tradingview.com/script/qyUwc2Al | //| Version : Pine Script v1/v2 (publicado Enero 14, 2015) | //| Licencia : Codigo abierto en TradingView | //| | //| --- INICIO DEL CODIGO PINE SCRIPT --- | //| | //| study(title="Coral Trend Indicator [LazyBear]", | //| shorttitle="CTI_LB", overlay=true) | //| src=close | //| sm =input(21, title="Smoothing Period") | //| cd = input(0.4, title="Constant D") | //| ebc=input(false, title="Color Bars") | //| ribm=input(false, title="Ribbon Mode") | //| | //| di = (sm - 1.0) / 2.0 + 1.0 | //| c1 = 2 / (di + 1.0) | //| c2 = 1 - c1 | //| c3 = 3.0 * (cd * cd + cd * cd * cd) | //| c4 = -3.0 * (2.0 * cd * cd + cd + cd * cd * cd) | //| c5 = 3.0 * cd + 1.0 + cd * cd * cd + 3.0 * cd * cd | //| | //| i1 = c1*src + c2*nz(i1[1]) | //| i2 = c1*i1 + c2*nz(i2[1]) | //| i3 = c1*i2 + c2*nz(i3[1]) | //| i4 = c1*i3 + c2*nz(i4[1]) | //| i5 = c1*i4 + c2*nz(i5[1]) | //| i6 = c1*i5 + c2*nz(i6[1]) | //| | //| bfr = -cd*cd*cd*i6 + c3*(i5) + c4*(i4) + c5*(i3) | //| | //| bfrC = bfr > nz(bfr[1]) ? green : | //| bfr < nz(bfr[1]) ? red : blue | //| | //| tc=ebc?gray:bfrC | //| plot(ribm?na:bfr, title="Trend", linewidth=3, | //| style=circles, color=tc) | //| bgcolor(ribm?bfrC:na, transp=50) | //| barcolor(ebc?bfrC:na) | //| | //| --- FIN DEL CODIGO PINE SCRIPT --- | //| | //| ================================================================ | //| CORRESPONDENCIA PINE SCRIPT -> MQL4 | //| ================================================================ | //| | //| Pine: src = close | //| MQL4: GetPrice(shift) con PRICE_CLOSE por defecto | //| Usa arrays predefinidos Open/High/Low/Close directamente | //| | //| Pine: i1 = c1*src + c2*nz(i1[1]) | //| MQL4: g_i1[i] = g_c1 * src + g_c2 * g_i1[i+1] | //| nz() retorna 0 en Pine; MQL4 usa seedPrice como semilla | //| para evitar contaminacion por ceros en buffers internos | //| NOTA: i+1 en MQL4 = barra anterior (indexacion inversa) | //| | //| Pine: bfr = -cd*cd*cd*i6 + c3*i5 + c4*i4 + c5*i3 | //| MQL4: bfr = -g_cd3*g_i6[i] + g_c3*g_i5[i] + ... | //| Coeficientes pre-calculados en OnInit() para eficiencia | //| | //| Pine: bfrC = bfr > nz(bfr[1]) ? green : ... | //| MQL4: Comparacion bfr vs bfrPrev -> asignar a g_bufferUp/Down | //| MQL4 no tiene DRAW_COLOR_LINE, se usan 3 buffers separados | //| con EMPTY_VALUE en las barras donde no aplican | //| | //| Pine: barcolor(ebc?bfrC:na) | //| MQL4: No implementado (requiere objetos graficos que son lentos) | //| Alternativa: usar el color de los 3 buffers como referencia| //| | //| Pine: plot(..., style=circles, ...) | //| MQL4: DRAW_LINE (linea continua; MQL4 no soporta DRAW_ARROW | //| con estilo circulo de forma nativa con grosor > 1) | //| | //| DIFERENCIAS TECNICAS: | //| - Pine inicializa series con nz()=0; MQL4 usa seedPrice como | //| semilla (el precio de la barra mas antigua) para estabilidad | //| - Pine procesa oldest->newest; MQL4 itera de indice alto a bajo | //| (pasado a presente), donde i+1 = barra anterior temporal | //| - El indicador NO repinta: alertas solo en vela cerrada (idx 1) | //| - Se agrego selector de precio aplicado (no existe en original) | //| - Se agrego sistema de alertas multi-canal (no existe en original)| //| - Ribbon Mode no implementado (requiere indicator_separate_window)| //| - Color Bars no implementado (DRAW_COLOR_CANDLES no existe en | //| MQL4; requeriria objetos graficos con impacto en rendimiento) | //| - Para continuidad visual en los cambios de color, se escribe | //| el valor bfrPrev en el buffer activo de la barra i+1 si estaba | //| vacio, creando un "puente" que conecta los segmentos | //| | //+------------------------------------------------------------------+