Warrior_EA/CustomIndicators/ADZigZag.mq5

301 lines
10 KiB
MQL5
Raw Permalink Normal View History

//+------------------------------------------------------------------+
//| ADZigZag.mq5 |
//| AD Institutional Indicators |
//+------------------------------------------------------------------+
// Renamed/rebranded copy of MetaQuotes' stock ZigZag.mq5 (Copyright 2000-2026, MetaQuotes Ltd.,
// https://www.mql5.com) - file, property, and identifier names only; the pivot-detection algorithm
// itself (Depth/Deviation/Backstep scan, extreme tracking, final-selection state machine) is
// untouched. Used by CExpertSignalAIBase as the ground-truth source for "is this bar a confirmed
// ZigZag reversal" training labels (see AdvanceZigZagLabelState() in ExpertSignalAIBase.mqh) -
// replacing the old hand-rolled fractal/deviation-%/ATR-trend-context approximation of a ZigZag
// with the real, well-known indicator, at its own stock default settings (Depth=12, Deviation=5,
// Backstep=3).
#property copyright "AD Institutional Indicators"
#property link ""
#property version "1.00"
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 1
//--- plot ADZigZag
#property indicator_label1 "ADZigZag"
#property indicator_type1 DRAW_SECTION
#property indicator_color1 clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//--- input parameters
input int InpDepth = 12; // Depth
input int InpDeviation = 5; // Deviation
input int InpBackstep = 3; // Back Step
//--- indicator buffers
double ADZZBuffer[]; // main buffer
double ADZZHighMapBuffer[]; // ZigZag high extremes (peaks)
double ADZZLowMapBuffer[]; // ZigZag low extremes (bottoms)
int ADZZExtRecalc = 3; // number of last extremes for recalculation
enum EnADZZSearchMode
{
ADZZ_Extremum = 0, // searching for the first extremum
ADZZ_Peak = 1, // searching for the next ZigZag peak
ADZZ_Bottom = -1 // searching for the next ZigZag bottom
};
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
//--- indicator buffers mapping
SetIndexBuffer(0, ADZZBuffer, INDICATOR_DATA);
SetIndexBuffer(1, ADZZHighMapBuffer, INDICATOR_CALCULATIONS);
SetIndexBuffer(2, ADZZLowMapBuffer, INDICATOR_CALCULATIONS);
//--- set short name and digits
string short_name = StringFormat("ADZigZag(%d,%d,%d)", InpDepth, InpDeviation, InpBackstep);
IndicatorSetString(INDICATOR_SHORTNAME, short_name);
PlotIndexSetString(0, PLOT_LABEL, short_name);
IndicatorSetInteger(INDICATOR_DIGITS, _Digits);
//--- set an empty value
PlotIndexSetDouble(0, PLOT_EMPTY_VALUE, 0.0);
}
//+------------------------------------------------------------------+
//| ADZigZag calculation |
//+------------------------------------------------------------------+
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[])
{
if(rates_total < 100)
return(0);
//---
int i = 0;
int start = 0, extreme_counter = 0, extreme_search = ADZZ_Extremum;
int shift = 0, back = 0, last_high_pos = 0, last_low_pos = 0;
double val = 0, res = 0;
double curlow = 0, curhigh = 0, last_high = 0, last_low = 0;
//--- initializing
if(prev_calculated == 0)
{
ArrayInitialize(ADZZBuffer, 0.0);
ArrayInitialize(ADZZHighMapBuffer, 0.0);
ArrayInitialize(ADZZLowMapBuffer, 0.0);
start = InpDepth;
}
//--- ADZigZag was already calculated before
if(prev_calculated > 0)
{
i = rates_total - 1;
//--- searching for the third extremum from the last uncompleted bar
while(extreme_counter < ADZZExtRecalc && i > rates_total - 100)
{
res = ADZZBuffer[i];
if(res != 0.0)
extreme_counter++;
i--;
}
i++;
start = i;
//--- what type of extremum we search for
if(ADZZLowMapBuffer[i] != 0.0)
{
curlow = ADZZLowMapBuffer[i];
extreme_search = ADZZ_Peak;
}
else
{
curhigh = ADZZHighMapBuffer[i];
extreme_search = ADZZ_Bottom;
}
//--- clear indicator values
for(i = start + 1; i < rates_total && !IsStopped(); i++)
{
ADZZBuffer[i] = 0.0;
ADZZLowMapBuffer[i] = 0.0;
ADZZHighMapBuffer[i] = 0.0;
}
}
//--- searching for high and low extremes
for(shift = start; shift < rates_total && !IsStopped(); shift++)
{
//--- low
val = low[Lowest(low, InpDepth, shift)];
if(val == last_low)
val = 0.0;
else
{
last_low = val;
if((low[shift] - val) > InpDeviation * _Point)
val = 0.0;
else
{
for(back = 1; back <= InpBackstep; back++)
{
res = ADZZLowMapBuffer[shift - back];
if((res != 0) && (res > val))
ADZZLowMapBuffer[shift - back] = 0.0;
}
}
}
if(low[shift] == val)
ADZZLowMapBuffer[shift] = val;
else
ADZZLowMapBuffer[shift] = 0.0;
//--- high
val = high[Highest(high, InpDepth, shift)];
if(val == last_high)
val = 0.0;
else
{
last_high = val;
if((val - high[shift]) > InpDeviation * _Point)
val = 0.0;
else
{
for(back = 1; back <= InpBackstep; back++)
{
res = ADZZHighMapBuffer[shift - back];
if((res != 0) && (res < val))
ADZZHighMapBuffer[shift - back] = 0.0;
}
}
}
if(high[shift] == val)
ADZZHighMapBuffer[shift] = val;
else
ADZZHighMapBuffer[shift] = 0.0;
}
//--- set last values
if(extreme_search == 0) // undefined values
{
last_low = 0.0;
last_high = 0.0;
}
else
{
last_low = curlow;
last_high = curhigh;
}
//--- final selection of extreme points for ADZigZag
for(shift = start; shift < rates_total && !IsStopped(); shift++)
{
res = 0.0;
switch(extreme_search)
{
case ADZZ_Extremum:
if(last_low == 0.0 && last_high == 0.0)
{
if(ADZZHighMapBuffer[shift] != 0)
{
last_high = high[shift];
last_high_pos = shift;
extreme_search = ADZZ_Bottom;
ADZZBuffer[shift] = last_high;
res = 1;
}
if(ADZZLowMapBuffer[shift] != 0.0)
{
last_low = low[shift];
last_low_pos = shift;
extreme_search = ADZZ_Peak;
ADZZBuffer[shift] = last_low;
res = 1;
}
}
break;
case ADZZ_Peak:
if(ADZZLowMapBuffer[shift] != 0.0 && ADZZLowMapBuffer[shift] < last_low && ADZZHighMapBuffer[shift] == 0.0)
{
ADZZBuffer[last_low_pos] = 0.0;
last_low_pos = shift;
last_low = ADZZLowMapBuffer[shift];
ADZZBuffer[shift] = last_low;
res = 1;
}
if(ADZZHighMapBuffer[shift] != 0.0 && ADZZLowMapBuffer[shift] == 0.0)
{
last_high = ADZZHighMapBuffer[shift];
last_high_pos = shift;
ADZZBuffer[shift] = last_high;
extreme_search = ADZZ_Bottom;
res = 1;
}
break;
case ADZZ_Bottom:
if(ADZZHighMapBuffer[shift] != 0.0 && ADZZHighMapBuffer[shift] > last_high && ADZZLowMapBuffer[shift] == 0.0)
{
ADZZBuffer[last_high_pos] = 0.0;
last_high_pos = shift;
last_high = ADZZHighMapBuffer[shift];
ADZZBuffer[shift] = last_high;
}
if(ADZZLowMapBuffer[shift] != 0.0 && ADZZHighMapBuffer[shift] == 0.0)
{
last_low = ADZZLowMapBuffer[shift];
last_low_pos = shift;
ADZZBuffer[shift] = last_low;
extreme_search = ADZZ_Peak;
}
break;
default:
return(rates_total);
}
}
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| Search for the index of the highest bar |
//+------------------------------------------------------------------+
int Highest(const double &array[], const int depth, const int start)
{
if(start < 0)
return(0);
double max = array[start];
int index = start;
//--- start searching
for(int i = start - 1; i > start - depth && i >= 0; i--)
{
if(array[i] > max)
{
index = i;
max = array[i];
}
}
//--- return index of the highest bar
return(index);
}
//+------------------------------------------------------------------+
//| Search for the index of the lowest bar |
//+------------------------------------------------------------------+
int Lowest(const double &array[], const int depth, const int start)
{
if(start < 0)
return(0);
double min = array[start];
int index = start;
//--- start searching
for(int i = start - 1; i > start - depth && i >= 0; i--)
{
if(array[i] < min)
{
index = i;
min = array[i];
}
}
//--- return index of the lowest bar
return(index);
}
//+------------------------------------------------------------------+