HeikinAshi-Trend/Coral_Trend.mq4

615 lines
56 KiB
MQL4
Raw Permalink Normal View History

2026-04-16 08:34:54 -06:00
<EFBFBD><EFBFBD>//T%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%W%
//Q% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%W% Q%
//Q% <EFBFBD>%<EFBFBD>%T%P%P%P%]%Z%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%]%<EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%P%P%P%]%<EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%P%P%P%]%<EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%Q% Q%
//Q% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%T%]% <EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%T%]%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%T%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%Q% Q%
//Q% <EFBFBD>%<EFBFBD>%T%P%P%]% <EFBFBD>%<EFBFBD>%T%<EFBFBD>%<EFBFBD>%W% <EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%P%P%]% <EFBFBD>%<EFBFBD>%T%P%P%<EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q%<EFBFBD>%<EFBFBD>%Q%Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%Q% Q%
//Q% <EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%T%]% <EFBFBD>%<EFBFBD>%W%Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%T%]%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%T%]%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W%<EFBFBD>%<EFBFBD>%Q% <EFBFBD>%<EFBFBD>%Q%Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%W%Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%<EFBFBD>%T%]%<EFBFBD>%<EFBFBD>%Q% Z%<EFBFBD>%<EFBFBD>%<EFBFBD>%Q% Q%
//Q% Z%P%P%P%P%P%]%Z%P%]% Z%P%]% Z%P%P%P%P%]% Z%P%P%P%P%P%]% Z%P%P%P%P%P%]%Z%P%]% Z%P%]% Z%P%P%P%P%]% Z%P%P%P%P%]% Z%P%]% Z%P%P%]% Q%
//Z%P%P%P%P%P%P%P% Algorithms that observe P%P%P%P% Signals that speak P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%P%]%
//
//+------------------------------------------------------------------+
//| 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 |
//| |
//+------------------------------------------------------------------+