319 lines
No EOL
28 KiB
MQL5
319 lines
No EOL
28 KiB
MQL5
//╔════════════════════════════════════════════════════════════════════════╗
|
|
//║ ██████╗██╗ ██╗ █████╗ ██████╗ ██████╗ █████╗ █████╗ █████╗ ███╗ ██╗ ║
|
|
//║ ██╔═══╝╚██╗██╔╝██╔══██╗██╔══██╗██╔═══╝██╔══██╗██╔═══╝██╔══██╗████╗ ██║ ║
|
|
//║ █████╗ ╚███╔╝ ██║ ██║██████╔╝█████╗ ███████║██║ ██║ ██║██╔██╗██║ ║
|
|
//║ ██╔══╝ ██╔██╗ ██║ ██║██╔══██╗██╔══╝ ██╔══██║██║ ██║ ██║██║╚████║ ║
|
|
//║ ██████╗██╔╝ ██╗╚█████╔╝██████╔╝██████╗██║ ██║╚█████╗╚█████╔╝██║ ╚███║ ║
|
|
//║ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚════╝ ╚════╝ ╚═╝ ╚══╝ ║
|
|
//╚═══════ Algorithms that observe ════ Signals that speak ════════════════╝
|
|
//+------------------------------------------------------------------+
|
|
//| Réplica fiel del indicador "ADX and DI" de BeikabuOyaji |
|
|
//| TradingView Pine Script v4 → MQL5 |
|
|
//| Fuente: tradingview.com/script/VTPMMOrx-ADX-and-DI/ |
|
|
//| Licencia original: Mozilla Public License 2.0 |
|
|
//+------------------------------------------------------------------+
|
|
//| NOTAS TÉCNICAS: |
|
|
//| - Suavizado Wilder (α=1/N) para TR, +DM, -DM → DI+, DI- |
|
|
//| - SMA simple (media aritmética ventana deslizante) para ADX |
|
|
//| - Esta combinación híbrida NO coincide con iADX (usa EMA) |
|
|
//| ni con iADXWilder (usa SMMA para el ADX final) |
|
|
//| - Inicialización desde 0 (replica nz() de Pine Script) |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Exobeacon Labs"
|
|
#property link "https://www.exobeacon.com/"
|
|
#property version "1.0"
|
|
#property description "ADX and DI (by BeikabuOyaji) v1.1"
|
|
#property description "Exact replica of BeikabuOyaji's ADX and DI indicator."
|
|
#property description "Uses Wilder smoothing for DI and SMA for ADX."
|
|
#property description " "
|
|
#property description "〰〰〰〰〰((👽))〰〰〰〰〰"
|
|
#property description "🛸 mql5.com/en/users/ulisescalb"
|
|
#property description "🛸 github.com/Exobeacon-Labs"
|
|
#property strict
|
|
|
|
#property indicator_separate_window
|
|
#property indicator_buffers 7 // 3 visibles + 4 de cálculo interno
|
|
#property indicator_plots 3 // DI+, DI-, ADX
|
|
|
|
//--- Plot 0: DI+ (verde)
|
|
#property indicator_label1 "DI+"
|
|
#property indicator_type1 DRAW_LINE
|
|
#property indicator_color1 clrGreen
|
|
#property indicator_style1 STYLE_SOLID
|
|
#property indicator_width1 1
|
|
|
|
//--- Plot 1: DI- (rojo)
|
|
#property indicator_label2 "DI-"
|
|
#property indicator_type2 DRAW_LINE
|
|
#property indicator_color2 clrRed
|
|
#property indicator_style2 STYLE_SOLID
|
|
#property indicator_width2 1
|
|
|
|
//--- Plot 2: ADX (azul marino)
|
|
#property indicator_label3 "ADX"
|
|
#property indicator_type3 DRAW_LINE
|
|
#property indicator_color3 clrNavy
|
|
#property indicator_style3 STYLE_SOLID
|
|
#property indicator_width3 2
|
|
|
|
//--- Nivel horizontal por defecto (se sobreescribe dinámicamente en OnInit)
|
|
#property indicator_level1 20
|
|
#property indicator_levelcolor clrBlack
|
|
#property indicator_levelstyle STYLE_SOLID
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Parámetros de entrada |
|
|
//| len → InpPeriod (período de suavizado y SMA) |
|
|
//| th → InpThreshold (línea horizontal de referencia) |
|
|
//+------------------------------------------------------------------+
|
|
input int InpPeriod = 14; // Período (len)
|
|
input int InpThreshold = 20; // Umbral horizontal (th)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Buffers globales |
|
|
//+------------------------------------------------------------------+
|
|
//--- Buffers de datos (INDICATOR_DATA: visibles, accesibles vía CopyBuffer)
|
|
double DIPlusBuffer[]; // Buffer 0 → Plot 0: DI+
|
|
double DIMinusBuffer[]; // Buffer 1 → Plot 1: DI-
|
|
double ADXBuffer[]; // Buffer 2 → Plot 2: ADX
|
|
|
|
//--- Buffers de cálculo interno (INDICATOR_CALCULATIONS: no visibles)
|
|
double SmoothedTRBuffer[]; // Buffer 3: True Range suavizado (Wilder)
|
|
double SmoothedDMPlusBuffer[]; // Buffer 4: +DM suavizado (Wilder)
|
|
double SmoothedDMMinusBuffer[]; // Buffer 5: -DM suavizado (Wilder)
|
|
double DXBuffer[]; // Buffer 6: DX (entrada para SMA → ADX)
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Inicialización del indicador |
|
|
//+------------------------------------------------------------------+
|
|
int OnInit()
|
|
{
|
|
//--- Validación de parámetros
|
|
if(InpPeriod < 1)
|
|
{
|
|
PrintFormat("ADXandDI: Error - Período (%d) debe ser >= 1", InpPeriod);
|
|
return(INIT_PARAMETERS_INCORRECT);
|
|
}
|
|
|
|
//--- Asignar buffers de datos (plots)
|
|
SetIndexBuffer(0, DIPlusBuffer, INDICATOR_DATA);
|
|
SetIndexBuffer(1, DIMinusBuffer, INDICATOR_DATA);
|
|
SetIndexBuffer(2, ADXBuffer, INDICATOR_DATA);
|
|
|
|
//--- Asignar buffers de cálculo interno
|
|
SetIndexBuffer(3, SmoothedTRBuffer, INDICATOR_CALCULATIONS);
|
|
SetIndexBuffer(4, SmoothedDMPlusBuffer, INDICATOR_CALCULATIONS);
|
|
SetIndexBuffer(5, SmoothedDMMinusBuffer, INDICATOR_CALCULATIONS);
|
|
SetIndexBuffer(6, DXBuffer, INDICATOR_CALCULATIONS);
|
|
|
|
//--- Configurar inicio de dibujo
|
|
// DI+/DI- requieren al menos 1 barra previa (para close[i-1], high[i-1])
|
|
// pero el suavizado de Wilder necesita ~InpPeriod barras para converger
|
|
// ADX = SMA(DX, InpPeriod) necesita InpPeriod valores de DX adicionales
|
|
PlotIndexSetInteger(0, PLOT_DRAW_BEGIN, InpPeriod); // DI+
|
|
PlotIndexSetInteger(1, PLOT_DRAW_BEGIN, InpPeriod); // DI-
|
|
PlotIndexSetInteger(2, PLOT_DRAW_BEGIN, InpPeriod * 2); // ADX
|
|
|
|
//--- Valor vacío para barras sin datos
|
|
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
|
PlotIndexSetDouble(1, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
|
PlotIndexSetDouble(2, PLOT_EMPTY_VALUE, EMPTY_VALUE);
|
|
|
|
//--- Configurar nivel horizontal según parámetro th
|
|
IndicatorSetInteger(INDICATOR_LEVELS, 1);
|
|
IndicatorSetDouble(INDICATOR_LEVELVALUE, 0, (double)InpThreshold);
|
|
IndicatorSetInteger(INDICATOR_LEVELCOLOR, 0, clrBlack);
|
|
IndicatorSetInteger(INDICATOR_LEVELSTYLE, 0, STYLE_SOLID);
|
|
|
|
//--- Precisión de decimales mostrados
|
|
IndicatorSetInteger(INDICATOR_DIGITS, 2);
|
|
|
|
//--- Nombre corto
|
|
string short_name = "ADX and DI (" + IntegerToString(InpPeriod) + ")";
|
|
IndicatorSetString(INDICATOR_SHORTNAME, short_name);
|
|
|
|
return(INIT_SUCCEEDED);
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Función principal de cálculo |
|
|
//| |
|
|
//| Algoritmo (réplica del Pine Script de BeikabuOyaji): |
|
|
//| |
|
|
//| 1. True Range = max(H-L, |H-C[1]|, |L-C[1]|) |
|
|
//| 2. +DM = (H-H[1] > L[1]-L) ? max(H-H[1], 0) : 0 |
|
|
//| -DM = (L[1]-L > H-H[1]) ? max(L[1]-L, 0) : 0 |
|
|
//| 3. Suavizado Wilder: |
|
|
//| S(i) = S(i-1) - S(i-1)/len + valor |
|
|
//| (equivale a running sum con decaimiento α=1/N) |
|
|
//| 4. DI+ = SmoothedDM+ / SmoothedTR * 100 |
|
|
//| DI- = SmoothedDM- / SmoothedTR * 100 |
|
|
//| 5. DX = |DI+ - DI-| / (DI+ + DI-) * 100 |
|
|
//| 6. ADX = SMA(DX, len) ← ¡SMA simple, NO Wilder/SMMA! |
|
|
//+------------------------------------------------------------------+
|
|
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 datos mínimos (necesitamos al menos 2 barras)
|
|
if(rates_total < 2)
|
|
return(0);
|
|
|
|
int start;
|
|
|
|
//=================================================================
|
|
// FASE 1: True Range, Movimiento Direccional, Suavizado Wilder,
|
|
// DI+, DI-, DX
|
|
//=================================================================
|
|
|
|
if(prev_calculated == 0)
|
|
{
|
|
//--- Primera ejecución completa: inicializar barra 0
|
|
// Pine Script nz() retorna 0 para valores inexistentes,
|
|
// así que los buffers suavizados empiezan desde 0
|
|
SmoothedTRBuffer[0] = 0.0;
|
|
SmoothedDMPlusBuffer[0] = 0.0;
|
|
SmoothedDMMinusBuffer[0] = 0.0;
|
|
DIPlusBuffer[0] = 0.0;
|
|
DIMinusBuffer[0] = 0.0;
|
|
DXBuffer[0] = 0.0;
|
|
ADXBuffer[0] = EMPTY_VALUE;
|
|
start = 1;
|
|
}
|
|
else
|
|
{
|
|
//--- Recalcular solo la última barra (o desde donde se quedó)
|
|
start = prev_calculated - 1;
|
|
}
|
|
|
|
//--- Bucle principal: indexación de izquierda a derecha (0 = más antigua)
|
|
for(int i = start; i < rates_total && !IsStopped(); i++)
|
|
{
|
|
//-------------------------------------------------------
|
|
// 1. True Range: max(H-L, |H-C₋₁|, |L-C₋₁|)
|
|
// Replica: max(max(high-low, abs(high-nz(close[1]))), abs(low-nz(close[1])))
|
|
//-------------------------------------------------------
|
|
double prev_close = close[i - 1];
|
|
double tr = MathMax(MathMax(high[i] - low[i],
|
|
MathAbs(high[i] - prev_close)),
|
|
MathAbs(low[i] - prev_close));
|
|
|
|
//-------------------------------------------------------
|
|
// 2. Movimiento Direccional (+DM, -DM)
|
|
// Regla de exclusividad mutua de Wilder:
|
|
// Solo el mayor movimiento (si es positivo) se cuenta
|
|
//-------------------------------------------------------
|
|
double up_move = high[i] - high[i - 1]; // UpMove
|
|
double down_move = low[i - 1] - low[i]; // DownMove
|
|
|
|
double dm_plus, dm_minus;
|
|
|
|
if(up_move > down_move && up_move > 0.0)
|
|
dm_plus = up_move;
|
|
else
|
|
dm_plus = 0.0;
|
|
|
|
if(down_move > up_move && down_move > 0.0)
|
|
dm_minus = down_move;
|
|
else
|
|
dm_minus = 0.0;
|
|
|
|
//-------------------------------------------------------
|
|
// 3. Suavizado de Wilder (forma running sum)
|
|
// S(i) = S(i-1) - S(i-1)/len + valor
|
|
// Equivalente a: S(i) = S(i-1) * (1 - 1/len) + valor
|
|
//-------------------------------------------------------
|
|
double prev_str = SmoothedTRBuffer[i - 1];
|
|
double prev_sdmp = SmoothedDMPlusBuffer[i - 1];
|
|
double prev_sdmm = SmoothedDMMinusBuffer[i - 1];
|
|
|
|
SmoothedTRBuffer[i] = prev_str - prev_str / InpPeriod + tr;
|
|
SmoothedDMPlusBuffer[i] = prev_sdmp - prev_sdmp / InpPeriod + dm_plus;
|
|
SmoothedDMMinusBuffer[i] = prev_sdmm - prev_sdmm / InpPeriod + dm_minus;
|
|
|
|
//-------------------------------------------------------
|
|
// 4. DI+ y DI- (en porcentaje)
|
|
// DI+ = SmoothedDM+ / SmoothedTR * 100
|
|
// DI- = SmoothedDM- / SmoothedTR * 100
|
|
//-------------------------------------------------------
|
|
double smoothed_tr = SmoothedTRBuffer[i];
|
|
|
|
if(smoothed_tr > 0.0)
|
|
{
|
|
DIPlusBuffer[i] = SmoothedDMPlusBuffer[i] / smoothed_tr * 100.0;
|
|
DIMinusBuffer[i] = SmoothedDMMinusBuffer[i] / smoothed_tr * 100.0;
|
|
}
|
|
else
|
|
{
|
|
DIPlusBuffer[i] = 0.0;
|
|
DIMinusBuffer[i] = 0.0;
|
|
}
|
|
|
|
//-------------------------------------------------------
|
|
// 5. DX = |DI+ - DI-| / (DI+ + DI-) * 100
|
|
//-------------------------------------------------------
|
|
double di_sum = DIPlusBuffer[i] + DIMinusBuffer[i];
|
|
|
|
if(di_sum > 0.0)
|
|
DXBuffer[i] = MathAbs(DIPlusBuffer[i] - DIMinusBuffer[i]) / di_sum * 100.0;
|
|
else
|
|
DXBuffer[i] = 0.0;
|
|
}
|
|
|
|
//=================================================================
|
|
// FASE 2: ADX = SMA(DX, len)
|
|
// Media aritmética simple de ventana deslizante sobre DX
|
|
// ¡CRÍTICO: es SMA, NO Wilder/SMMA/RMA!
|
|
//=================================================================
|
|
|
|
int adx_first_bar = InpPeriod; // Primera barra con ADX válido
|
|
// (necesita InpPeriod valores de DX: barras 1..InpPeriod)
|
|
int adx_start;
|
|
|
|
if(prev_calculated == 0)
|
|
{
|
|
//--- Marcar todas las barras sin ADX válido
|
|
for(int i = 0; i < MathMin(adx_first_bar, rates_total); i++)
|
|
ADXBuffer[i] = EMPTY_VALUE;
|
|
|
|
//--- Verificar que hay suficientes barras para calcular el primer SMA
|
|
if(rates_total <= adx_first_bar)
|
|
return(rates_total);
|
|
|
|
//--- Calcular el primer valor de ADX como SMA de DX[1..InpPeriod]
|
|
// DX es válido desde barra 1 (primera barra que tiene barra previa)
|
|
// Pine Script sma(DX, len) en la barra InpPeriod toma las barras
|
|
// [InpPeriod-len+1 .. InpPeriod] = [1 .. InpPeriod]
|
|
double sum = 0.0;
|
|
for(int j = 1; j <= InpPeriod; j++)
|
|
sum += DXBuffer[j];
|
|
ADXBuffer[adx_first_bar] = sum / InpPeriod;
|
|
|
|
adx_start = adx_first_bar + 1;
|
|
}
|
|
else
|
|
{
|
|
adx_start = MathMax(prev_calculated - 1, adx_first_bar + 1);
|
|
}
|
|
|
|
//--- Calcular SMA incremental para las barras restantes
|
|
// SMA(i) = SMA(i-1) + (DX[i] - DX[i-InpPeriod]) / InpPeriod
|
|
// Esto es algebraicamente equivalente a sumar los últimos InpPeriod
|
|
// valores de DX y dividir entre InpPeriod, pero es O(1) por barra
|
|
for(int i = adx_start; i < rates_total && !IsStopped(); i++)
|
|
{
|
|
double new_val = DXBuffer[i];
|
|
double old_val = DXBuffer[i - InpPeriod];
|
|
ADXBuffer[i] = ADXBuffer[i - 1] + (new_val - old_val) / InpPeriod;
|
|
}
|
|
|
|
return(rates_total);
|
|
}
|
|
//+------------------------------------------------------------------+ |