Impulse-MACD/Impulse_MACD.mq5

588 lignes
50 Kio
MQL5
Brut Lien permanent Vue normale Historique

2026-02-22 17:46:05 -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 : Impulse_MACD.mq5
// Origen : Port fiel del indicador "Impulse MACD [LazyBear]" de TradingView
// URL ref. : https://www.tradingview.com/script/qt6xLfLi-Impulse-MACD-LazyBear/
// Autor : LazyBear (Pine Script original, 2015)
// Port : Exobeacon Labs
//
// Descripci<EFBFBD>n de la l<EFBFBD>gica:
// El indicador combina una DEMA/ZLEMA r<EFBFBD>pida (sobre HLC3) con un canal
// de doble SMMA (sobre High y Low). El ImpulseMACD vale la distancia
// entre la ZLEMA y el borde del canal solo cuando la ZLEMA lo rompe.
// Si la ZLEMA permanece dentro del canal, el valor es 0 (zona neutra).
// La se<EFBFBD>al es una SMA del ImpulseMACD. El color del histograma refleja
// la posici<EFBFBD>n del precio (HLC3) respecto a la ZLEMA y al canal SMMA.
//
// Estructura de c<EFBFBD>lculo:
// 1. HLC3 = (High + Low + Close) / 3
// 2. hi = SMMA(High, lengthMA) <EFBFBD>! techo del canal
// 3. lo = SMMA(Low, lengthMA) <EFBFBD>! suelo del canal
// 4. mi = ZLEMA(HLC3, lengthMA) <EFBFBD>! DEMA: 2*EMA1 - EMA2
// 5. md = (mi>hi)?(mi-hi) : (mi<lo)?(mi-lo) : 0 <EFBFBD>! ImpulseMACD
// 6. sb = SMA(md, lengthSignal) <EFBFBD>! l<EFBFBD>nea de se<EFBFBD>al
// 7. sh = md - sb <EFBFBD>! histograma de diferencia
// 8. mdc = color seg<EFBFBD>n posici<EFBFBD>n de HLC3 vs mi y canal
//
#property copyright "Exobeacon Labs"
#property link "https://www.exobeacon.com/"
#property version "1.0"
#property description "Impulse MACD [LazyBear] v1.0"
#property description "MACD with SMMA channel filter - eliminates whipsaw in ranging markets"
#property description "ImpulseMACD = distance from ZLEMA (DEMA) to SMMA(H/L) channel boundary"
#property description "Signal = SMA(ImpulseMACD). Color encodes price position vs channel."
#property description "Based on LazyBear original Pine Script (TradingView, 2015)"
#property description " "
#property description "0000000000((=<3D>}<7D>))0000000000"
#property description "=<3D><><EFBFBD> mql5.com/en/users/ulisescalb"
#property description "=<3D><><EFBFBD> github.com/Exobeacon-Labs"
#property strict
//--- El indicador se muestra en ventana separada
#property indicator_separate_window
//--- N<EFBFBD>mero total de buffers: 4 de plot + 6 de c<EFBFBD>lculo interno = 10
#property indicator_buffers 10
#property indicator_plots 3
// ============================================================
// CONFIGURACI<EFBFBD>N DE PLOTS
// ============================================================
//--- Plot 0: ImpulseMACD (histograma con 4 colores din<EFBFBD>micos)
// Colores por <EFBFBD>ndice: 0=Lime, 1=Green, 2=Orange, 3=Red
#property indicator_type1 DRAW_COLOR_HISTOGRAM
#property indicator_color1 clrLime,clrGreen,clrOrange,clrRed
#property indicator_width1 2
#property indicator_label1 "ImpulseMACD"
//--- Plot 1: L<EFBFBD>nea de se<EFBFBD>al (SMA del ImpulseMACD)
#property indicator_type2 DRAW_LINE
#property indicator_color2 clrMaroon
#property indicator_width2 2
#property indicator_style2 STYLE_SOLID
#property indicator_label2 "Signal"
//--- Plot 2: Histograma de diferencia (ImpulseMACD - Se<EFBFBD>al)
#property indicator_type3 DRAW_HISTOGRAM
#property indicator_color3 clrDodgerBlue
#property indicator_width3 2
#property indicator_label3 "ImpulseHisto"
// ============================================================
// INPUTS
// ============================================================
input group "====== Impulse MACD Settings ======"
input int InpLengthMA = 34; // MA Period (SMMA channel + ZLEMA)
input int InpLengthSignal = 9; // Signal Period (SMA of ImpulseMACD)
input group "====== Alerts ======"
input bool InpEnableAlerts = false; // Enable alerts
input bool InpAlertPopup = true; // Alert: popup
input bool InpAlertSound = false; // Alert: sound
input bool InpAlertPush = false; // Alert: push notification
input bool InpAlertEmail = false; // Alert: email
input string InpSoundFile = "alert.wav"; // Sound file name
// ============================================================
// BUFFERS DE PLOT (<EFBFBD>ndices 0-3)
// ============================================================
double BufMACDData[]; // [0] Datos del histograma ImpulseMACD
double BufMACDColor[]; // [1] <EFBFBD>ndice de color del histograma
double BufSignal[]; // [2] L<EFBFBD>nea de se<EFBFBD>al
double BufHisto[]; // [3] Histograma de diferencia (md - sb)
// ============================================================
// BUFFERS DE C<EFBFBD>LCULO INTERNO (<EFBFBD>ndices 4-9)
// ============================================================
double BufHLC3[]; // [4] Precio t<EFBFBD>pico HLC3
double BufSmmaHigh[]; // [5] SMMA aplicada sobre High
double BufSmmaLow[]; // [6] SMMA aplicada sobre Low
double BufEMA1[]; // [7] Primera EMA de HLC3
double BufEMA2[]; // [8] EMA de la EMA1 (doble EMA para ZLEMA)
double BufZLEMA[]; // [9] ZLEMA = 2*EMA1 - EMA2 (equivalente a DEMA)
// ============================================================
// VARIABLES GLOBALES AUXILIARES
// ============================================================
//--- Control de alertas: evita duplicados en la misma vela
datetime g_lastAlertTime = 0;
//--- Constante del nombre corto para alertas y t<EFBFBD>tulo
string g_shortName = "";
// ============================================================
// OnInit
// ============================================================
int OnInit()
{
//--- Validar par<EFBFBD>metros de entrada
if(InpLengthMA < 2)
{
PrintFormat("ImpulseMACD: MA Period (%d) must be >= 2. Initialization failed.", InpLengthMA);
return(INIT_PARAMETERS_INCORRECT);
}
if(InpLengthSignal < 1)
{
PrintFormat("ImpulseMACD: Signal Period (%d) must be >= 1. Initialization failed.", InpLengthSignal);
return(INIT_PARAMETERS_INCORRECT);
}
// ---- Asignaci<EFBFBD>n de buffers de plot ----
// Buffer 0: datos del histograma ImpulseMACD
SetIndexBuffer(0, BufMACDData, INDICATOR_DATA);
// Buffer 1: <EFBFBD>ndices de color para el histograma
SetIndexBuffer(1, BufMACDColor, INDICATOR_COLOR_INDEX);
// Buffer 2: l<EFBFBD>nea de se<EFBFBD>al
SetIndexBuffer(2, BufSignal, INDICATOR_DATA);
// Buffer 3: histograma de diferencia
SetIndexBuffer(3, BufHisto, INDICATOR_DATA);
// ---- Asignaci<EFBFBD>n de buffers de c<EFBFBD>lculo interno ----
SetIndexBuffer(4, BufHLC3, INDICATOR_CALCULATIONS);
SetIndexBuffer(5, BufSmmaHigh, INDICATOR_CALCULATIONS);
SetIndexBuffer(6, BufSmmaLow, INDICATOR_CALCULATIONS);
SetIndexBuffer(7, BufEMA1, INDICATOR_CALCULATIONS);
SetIndexBuffer(8, BufEMA2, INDICATOR_CALCULATIONS);
SetIndexBuffer(9, BufZLEMA, INDICATOR_CALCULATIONS);
// ---- Valores vac<EFBFBD>os: usar EMPTY_VALUE para evitar basura visual ----
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
// ---- Inicio de dibujo (evita basura en las primeras barras) ----
// El ImpulseMACD requiere al menos (lengthMA) barras para el primer SMMA/EMA v<EFBFBD>lido
// La se<EFBFBD>al requiere adem<EFBFBD>s (lengthSignal - 1) barras adicionales
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpLengthMA);
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, InpLengthMA + InpLengthSignal - 1);
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpLengthMA + InpLengthSignal - 1);
// ---- Nombre corto del indicador en la ventana ----
g_shortName = StringFormat("IMACD_LB(%d,%d)", InpLengthMA, InpLengthSignal);
IndicatorSetString(INDICATOR_SHORTNAME, g_shortName);
// ---- D<EFBFBD>gitos de precisi<EFBFBD>n ----
IndicatorSetInteger(INDICATOR_DIGITS, _Digits + 2);
// ---- Nivel de referencia en cero ----
IndicatorSetInteger(INDICATOR_LEVELS, 1);
IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, 0.0);
IndicatorSetInteger(INDICATOR_LEVELCOLOR, 0, clrGray);
IndicatorSetInteger(INDICATOR_LEVELSTYLE, 0, STYLE_SOLID);
IndicatorSetInteger(INDICATOR_LEVELWIDTH, 0, 1);
return(INIT_SUCCEEDED);
}
// ============================================================
// OnDeinit
// ============================================================
void OnDeinit(const int reason)
{
//--- Limpiar el comentario en el gr<EFBFBD>fico si se hubiera usado
Comment("");
}
// ============================================================
// OnCalculate
// ============================================================
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 m<EFBFBD>nimo de barras necesarias para un c<EFBFBD>lculo v<EFBFBD>lido
// Se necesita: lengthMA (para SMMA/EMA) + lengthSignal (para SMA de se<EFBFBD>al)
if(rates_total < InpLengthMA + InpLengthSignal)
return(0);
// ============================================================
// PASO 1: Calcular HLC3 = (High + Low + Close) / 3
// ============================================================
// Si es rec<EFBFBD>lculo completo, procesar desde la barra 0
// Si es actualizaci<EFBFBD>n incremental, solo recalcular la <EFBFBD>ltima barra
int startHLC3 = (prev_calculated > 0) ? (prev_calculated - 1) : 0;
for(int i = startHLC3; i < rates_total; i++)
BufHLC3[i] = (high[i] + low[i] + close[i]) / 3.0;
// ============================================================
// PASO 2: SMMA de High <EFBFBD>! techo del canal (BufSmmaHigh)
// PASO 3: SMMA de Low <EFBFBD>! suelo del canal (BufSmmaLow)
// ============================================================
// SMMA: primer valor = SMA(N), luego SMMA[i] = (SMMA[i-1]*(N-1) + src[i]) / N
CalcSMMA(high, BufSmmaHigh, InpLengthMA, rates_total, prev_calculated);
CalcSMMA(low, BufSmmaLow, InpLengthMA, rates_total, prev_calculated);
// ============================================================
// PASO 4: ZLEMA de HLC3 = 2*EMA1 - EMA2 (equivale a DEMA de Mulloy)
// ============================================================
// EMA1 = EMA(HLC3, N)
CalcEMA(BufHLC3, BufEMA1, InpLengthMA, rates_total, prev_calculated);
// EMA2 = EMA(EMA1, N)  doble suavizado
CalcEMA(BufEMA1, BufEMA2, InpLengthMA, rates_total, prev_calculated);
// ZLEMA[i] = 2*EMA1[i] - EMA2[i]
// Las primeras (lengthMA - 1) barras de EMA1 y EMA2 no son v<EFBFBD>lidas
int startZL = (prev_calculated > 0) ? (prev_calculated - 1) : (InpLengthMA - 1);
for(int i = startZL; i < rates_total; i++)
BufZLEMA[i] = 2.0 * BufEMA1[i] - BufEMA2[i];
// ============================================================
// PASO 5: ImpulseMACD (md)  filtro de canal
// md = (mi > hi) ? (mi - hi) : (mi < lo) ? (mi - lo) : 0
// Anula la se<EFBFBD>al cuando la ZLEMA permanece dentro del canal SMMA
// ============================================================
int startMD = (prev_calculated > 0) ? (prev_calculated - 1) : (InpLengthMA - 1);
for(int i = startMD; i < rates_total; i++)
{
double mi = BufZLEMA[i];
double hi_val = BufSmmaHigh[i];
double lo_val = BufSmmaLow[i];
if(mi > hi_val)
BufMACDData[i] = mi - hi_val; // Impulso alcista: ZLEMA sobre techo del canal
else if(mi < lo_val)
BufMACDData[i] = mi - lo_val; // Impulso bajista: ZLEMA bajo suelo del canal
else
BufMACDData[i] = 0.0; // Zona neutra: sin se<EFBFBD>al
}
// ============================================================
// PASO 6: Se<EFBFBD>al = SMA(ImpulseMACD, lengthSignal)
// ============================================================
// El primer valor v<EFBFBD>lido de md est<EFBFBD> en el <EFBFBD>ndice (lengthMA - 1)
// La se<EFBFBD>al necesita adem<EFBFBD>s (lengthSignal - 1) barras de md
int firstValidMD = InpLengthMA - 1;
int firstValidSig = firstValidMD + InpLengthSignal - 1;
int startSig = (prev_calculated > 0)
? MathMax(firstValidSig, prev_calculated - 1)
: firstValidSig;
for(int i = startSig; i < rates_total; i++)
{
//--- SMA simple sobre la ventana de (lengthSignal) valores de md
double sum = 0.0;
for(int j = 0; j < InpLengthSignal; j++)
sum += BufMACDData[i - j];
BufSignal[i] = sum / (double)InpLengthSignal;
}
// ============================================================
// PASO 7: Histograma de diferencia y l<EFBFBD>gica de colores
// ============================================================
// El histograma sh = md - sb
// El color depende de la posici<EFBFBD>n de HLC3 respecto a mi y el canal:
// src > mi && src > hi <EFBFBD>! <EFBFBD>ndice 0 (Lime) alcista fuerte
// src > mi && src <= hi <EFBFBD>! <EFBFBD>ndice 1 (Green) alcista moderado
// src <= mi && src >= lo<EFBFBD>! <EFBFBD>ndice 2 (Orange) bajista moderado
// src <= mi && src < lo <EFBFBD>! <EFBFBD>ndice 3 (Red) bajista fuerte
int startFinal = (prev_calculated > 0)
? MathMax(firstValidSig, prev_calculated - 1)
: firstValidSig;
for(int i = startFinal; i < rates_total; i++)
{
//--- Histograma de diferencia
BufHisto[i] = BufMACDData[i] - BufSignal[i];
//--- Variables locales para legibilidad
double src_val = BufHLC3[i];
double mi = BufZLEMA[i];
double hi_val = BufSmmaHigh[i];
double lo_val = BufSmmaLow[i];
//--- L<EFBFBD>gica de color (r<EFBFBD>plica exacta del Pine Script original):
// mdc = src>mi ? src>hi ? lime : green : src<lo ? red : orange
if(src_val > mi)
{
if(src_val > hi_val)
BufMACDColor[i] = 0; // Lime  alcista fuerte
else
BufMACDColor[i] = 1; // Green  alcista moderado
}
else
{
if(src_val < lo_val)
BufMACDColor[i] = 3; // Red  bajista fuerte
else
BufMACDColor[i] = 2; // Orange  bajista moderado
}
}
// ============================================================
// PASO 8: Sistema de alertas
// ============================================================
if(InpEnableAlerts && rates_total >= 2)
{
//--- Solo alertar en la <EFBFBD>ltima vela CERRADA (<EFBFBD>ndice rates_total - 2)
// para evitar repintado en la vela actual
int lastClosed = rates_total - 2;
double md_cur = BufMACDData[lastClosed];
double md_prev = (lastClosed > 0) ? BufMACDData[lastClosed - 1] : 0.0;
double sb_cur = BufSignal[lastClosed];
double sb_prev = (lastClosed > 0) ? BufSignal[lastClosed - 1] : 0.0;
//--- Evitar alertas duplicadas en la misma vela
if(time[lastClosed] != g_lastAlertTime)
{
string alertMsg = "";
//--- Cruce alcista: ImpulseMACD cruza sobre la l<EFBFBD>nea de se<EFBFBD>al
// crossover(md, sb): md_prev < sb_prev && md_cur >= sb_cur
if(md_prev < sb_prev && md_cur >= sb_cur)
{
alertMsg = StringFormat("%s | %s %s | Bullish crossover: ImpulseMACD crossed above Signal",
g_shortName, _Symbol,
EnumToString((ENUM_TIMEFRAMES)Period()));
}
//--- Cruce bajista: ImpulseMACD cruza bajo la l<EFBFBD>nea de se<EFBFBD>al
// crossunder(md, sb): md_prev > sb_prev && md_cur <= sb_cur
else if(md_prev > sb_prev && md_cur <= sb_cur)
{
alertMsg = StringFormat("%s | %s %s | Bearish crossunder: ImpulseMACD crossed below Signal",
g_shortName, _Symbol,
EnumToString((ENUM_TIMEFRAMES)Period()));
}
//--- Cruce de cero al alza: ImpulseMACD pasa de negativo/cero a positivo
else if(md_prev <= 0.0 && md_cur > 0.0)
{
alertMsg = StringFormat("%s | %s %s | Bullish impulse: ImpulseMACD crossed above zero",
g_shortName, _Symbol,
EnumToString((ENUM_TIMEFRAMES)Period()));
}
//--- Cruce de cero a la baja: ImpulseMACD pasa de positivo a negativo/cero
else if(md_prev >= 0.0 && md_cur < 0.0)
{
alertMsg = StringFormat("%s | %s %s | Bearish impulse: ImpulseMACD crossed below zero",
g_shortName, _Symbol,
EnumToString((ENUM_TIMEFRAMES)Period()));
}
//--- Disparar alerta si hay mensaje
if(alertMsg != "")
{
g_lastAlertTime = time[lastClosed];
if(InpAlertPopup)
Alert(alertMsg);
if(InpAlertSound)
PlaySound(InpSoundFile);
if(InpAlertPush)
SendNotification(alertMsg);
if(InpAlertEmail)
SendMail(g_shortName + " Alert", alertMsg);
}
}
}
return(rates_total);
}
// ============================================================
// FUNCI<EFBFBD>N: CalcSMMA
// Calcula la SMMA (Smoothed Moving Average) recursiva.
// Equivale a MODE_SMMA en MetaTrader / RMA en Pine Script.
//
// F<EFBFBD>rmula:
// - Primera barra v<EFBFBD>lida (idx = period-1): SMMA = SMA(src, period)
// - Barras siguientes: SMMA[i] = (SMMA[i-1] * (period-1) + src[i]) / period
//
// Par<EFBFBD>metros:
// src <EFBFBD>! array fuente (High o Low)
// dst <EFBFBD>! array destino
// period <EFBFBD>! per<EFBFBD>odo de suavizado
// rates_total <EFBFBD>! n<EFBFBD>mero total de barras disponibles
// prev_calc <EFBFBD>! barras calculadas en la llamada anterior
// ============================================================
void CalcSMMA(const double &src[], double &dst[],
int period, int rates_total, int prev_calc)
{
if(prev_calc == 0)
{
//--- Inicializaci<EFBFBD>n completa desde cero
//--- La primera barra v<EFBFBD>lida (idx = period-1) se inicializa con SMA simple
double sum = 0.0;
for(int j = 0; j < period; j++)
sum += src[j];
dst[period - 1] = sum / (double)period;
//--- Recursi<EFBFBD>n SMMA desde la barra siguiente al primer valor v<EFBFBD>lido
for(int i = period; i < rates_total; i++)
dst[i] = (dst[i - 1] * (double)(period - 1) + src[i]) / (double)period;
}
else
{
//--- Actualizaci<EFBFBD>n incremental: solo recalcular desde la <EFBFBD>ltima barra conocida
// El valor anterior (prev_calc - 2) ya fue calculado y es v<EFBFBD>lido como semilla
for(int i = prev_calc - 1; i < rates_total; i++)
dst[i] = (dst[i - 1] * (double)(period - 1) + src[i]) / (double)period;
}
}
// ============================================================
// FUNCI<EFBFBD>N: CalcEMA
// Calcula la EMA (Exponential Moving Average) recursiva.
//
// F<EFBFBD>rmula:
// k = 2 / (period + 1)
// - Primera barra v<EFBFBD>lida (idx = period-1): EMA = SMA(src, period)
// - Barras siguientes: EMA[i] = src[i]*k + EMA[i-1]*(1-k)
//
// Par<EFBFBD>metros:
// src <EFBFBD>! array fuente (puede ser BufHLC3 o BufEMA1)
// dst <EFBFBD>! array destino
// period <EFBFBD>! per<EFBFBD>odo de suavizado
// rates_total <EFBFBD>! n<EFBFBD>mero total de barras disponibles
// prev_calc <EFBFBD>! barras calculadas en la llamada anterior
//
// Nota: Se usa la misma l<EFBFBD>gica de inicializaci<EFBFBD>n que Pine Script,
// que inicializa la primera barra de EMA con SMA(N).
// ============================================================
void CalcEMA(const double &src[], double &dst[],
int period, int rates_total, int prev_calc)
{
const double k = 2.0 / (double)(period + 1);
if(prev_calc == 0)
{
//--- Primer valor v<EFBFBD>lido = SMA simple de los primeros N elementos
double sum = 0.0;
for(int j = 0; j < period; j++)
sum += src[j];
dst[period - 1] = sum / (double)period;
//--- Recursi<EFBFBD>n EMA est<EFBFBD>ndar
for(int i = period; i < rates_total; i++)
dst[i] = src[i] * k + dst[i - 1] * (1.0 - k);
}
else
{
//--- Actualizaci<EFBFBD>n incremental
for(int i = prev_calc - 1; i < rates_total; i++)
dst[i] = src[i] * k + dst[i - 1] * (1.0 - k);
}
}
// ============================================================
// ============================================================
//
// REFERENCIA: C<EFBFBD>DIGO PINE SCRIPT ORIGINAL
//
// Indicador: Impulse MACD [LazyBear]
// Autor : LazyBear
// Fecha : 29 de abril de 2015
// URL : https://www.tradingview.com/script/qt6xLfLi-Impulse-MACD-LazyBear/
// Versi<EFBFBD>n : Pine Script v2 (sin anotaci<EFBFBD>n @version expl<EFBFBD>cita)
// Licencia : C<EFBFBD>digo abierto en TradingView
//
// ============================================================
//
// //
// // @author LazyBear
// // List of my public indicators: http://bit.ly/1LQaPK8
// // List of my app-store indicators: http://blog.tradingview.com/?p=970
// //
// study("Impulse MACD [LazyBear]", shorttitle="IMACD_LB", overlay=false)
// lengthMA = input(34)
// lengthSignal = input(9)
//
// calc_smma(src, len) =>
// smma=na(smma[1]) ? sma(src, len) : (smma[1] * (len - 1) + src) / len
// smma
//
// calc_zlema(src, length) =>
// ema1=ema(src, length)
// ema2=ema(ema1, length)
// d=ema1-ema2
// ema1+d
//
// src=hlc3
// hi=calc_smma(high, lengthMA)
// lo=calc_smma(low, lengthMA)
// mi=calc_zlema(src, lengthMA)
//
// md=(mi>hi)? (mi-hi) : (mi<lo) ? (mi - lo) : 0
// sb=sma(md, lengthSignal)
// sh=md-sb
// mdc=src>mi?src>hi?lime:green:src<lo?red:orange
//
// plot(0, color=gray, linewidth=1, title="MidLine")
// plot(md, color=mdc, linewidth=2, title="ImpulseMACD", style=histogram)
// plot(sh, color=blue, linewidth=2, title="ImpulseHisto", style=histogram)
// plot(sb, color=maroon, linewidth=2, title="ImpulseMACDCDSignal")
//
// ebc=input(false, title="Enable bar colors")
// barcolor(ebc?mdc:na)
//
// ============================================================
//
// NOTAS DE CONVERSI<EFBFBD>N (Pine Script <EFBFBD>! MQL5)
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// 1. ZLEMA vs DEMA:
// LazyBear llama "ZLEMA" a la funci<EFBFBD>n calc_zlema, pero la implementaci<EFBFBD>n
// (ema1 + d, donde d = ema1 - ema2) es matem<EFBFBD>ticamente id<EFBFBD>ntica a la
// DEMA (Double Exponential MA) de Patrick Mulloy: 2*EMA1 - EMA2.
// La implementaci<EFBFBD>n MQL5 refleja la f<EFBFBD>rmula real correctamente.
//
// 2. Direcci<EFBFBD>n de arrays:
// En Pine Script, index 0 = barra actual, [1] = barra anterior.
// En MQL5 OnCalculate (sin ArraySetAsSeries), index 0 = barra m<EFBFBD>s
// antigua, rates_total-1 = barra actual. Los c<EFBFBD>lculos recursivos
// de SMMA y EMA se benefician de esta direcci<EFBFBD>n cronol<EFBFBD>gica natural
// ya que necesitan el valor [i-1] como valor previo.
//
// 3. Inicializaci<EFBFBD>n de medias recursivas:
// Pine Script inicializa SMMA con sma(src, len) en la primera barra
// (na(smma[1])). Esta implementaci<EFBFBD>n replica ese comportamiento exacto:
// la semilla es una SMA simple de los primeros N valores.
// El mismo criterio aplica a la EMA. Esto puede generar diferencias
// menores en las primeras 50-100 barras (efecto de calentamiento).
// Se recomienda cargar al menos 500 barras de historial adicional.
//
// 4. Colores:
// El histograma ImpulseMACD usa DRAW_COLOR_HISTOGRAM con un buffer
// extra de tipo INDICATOR_COLOR_INDEX. Los <EFBFBD>ndices 0-3 mapean a
// los colores Lime, Green, Orange, Red en ese orden, replicando
// exactamente la l<EFBFBD>gica ternaria del Pine Script original.
//
// 5. Coloraci<EFBFBD>n de velas (barcolor):
// El input "Enable bar colors" del original no est<EFBFBD> implementado en
// esta versi<EFBFBD>n. La coloraci<EFBFBD>n de velas en MQL5 requiere un indicador
// separado de tipo DRAW_COLOR_CANDLES con 5 buffers adicionales.
// Se puede implementar en una versi<EFBFBD>n futura si el usuario lo requiere.
//
// 6. La l<EFBFBD>nea de referencia en cero est<EFBFBD> implementada mediante
// IndicatorSetInteger(INDICATOR_LEVELS) en lugar de un plot adicional,
// lo que es m<EFBFBD>s eficiente en MQL5.
//
// 7. Alertas:
// El indicador original no incluye alertas. Esta implementaci<EFBFBD>n a<EFBFBD>ade
// un sistema de alertas multi-canal en los cruces de la l<EFBFBD>nea de se<EFBFBD>al
// y en los cruces del nivel cero, como extensi<EFBFBD>n operacional est<EFBFBD>ndar
// de Exobeacon Labs.
//
// ============================================================