614 lines
56 KiB
MQL4
614 lines
56 KiB
MQL4
//╔════════════════════════════════════════════════════════════════════════╗
|
|
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
|
|
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
|
|
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
|
|
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
|
|
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
|
|
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
|
|
//╚═══════ 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 |
|
|
//| |
|
|
//+------------------------------------------------------------------+
|