//±-----------------------------------------------------------------+
//| fbi.mq5 |
//±-----------------------------------------------------------------+
#property copyright “Copyright 2022, icepsyche”
#property link “https://www.mql5.com”
#property version “1.00”
#property indicator_chart_window
#property indicator_buffers 3
#property indicator_plots 1
//— plot ZigZag
#property indicator_label1 “fZigZag”
#property indicator_type1 DRAW_SECTION
#property indicator_color1 clrRed
#property indicator_style1 STYLE_SOLID
#property indicator_width1 1
//— input parameters
input int InpDepth =5; // Depth
//— indicator buffers
double ZigZagBuffer[]; // main buffer
double HighMapBuffer[]; // ZigZag high extremes (peaks)
double LowMapBuffer[]; // ZigZag low extremes (bottoms)
int ExtRecalc=3; // number of last extremes for recalculation
enum EnSearchMode
{
Extremum=0, // searching for the first extremum
Peak=1, // searching for the next ZigZag peak
Bottom=-1 // searching for the next ZigZag bottom
};
//±-----------------------------------------------------------------+
//| Custom indicator initialization function |
//±-----------------------------------------------------------------+
void OnInit()
{
//— indicator buffers mapping
SetIndexBuffer(0,ZigZagBuffer,INDICATOR_DATA);
SetIndexBuffer(1,HighMapBuffer,INDICATOR_CALCULATIONS);
SetIndexBuffer(2,LowMapBuffer,INDICATOR_CALCULATIONS);
//— set short name and digits
string short_name=StringFormat(“ZigZag(%d)”,InpDepth);
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);
}
//±-----------------------------------------------------------------+
//| ZigZag 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=Extremum;
int shift=0,last_high_pos=0,last_low_pos=0;
double res=0;
double curlow=0,curhigh=0,last_high=0,last_low=0;
//— initializing
if(prev_calculated==0)
{
ArrayInitialize(ZigZagBuffer,0.0);
ArrayInitialize(HighMapBuffer,0.0);
ArrayInitialize(LowMapBuffer,0.0);
start=InpDepth;
}
//— ZigZag 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<ExtRecalc && i>rates_total-100)
{
res=ZigZagBuffer[i];
if(res!=0.0)
extreme_counter++;
i–;
}
i++;
start=i;
//--- what type of exremum we search for
if(LowMapBuffer[i]!=0.0)
{
curlow=LowMapBuffer[i];
extreme_search=Peak;
}
else
{
curhigh=HighMapBuffer[i];
extreme_search=Bottom;
}
//--- clear indicator values
for(i=start+1; i<rates_total && !IsStopped(); i++)
{
ZigZagBuffer[i] =0.0;
LowMapBuffer[i] =0.0;
HighMapBuffer[i]=0.0;
}
}
//— searching for high and low extremes
for(shift=start+1; shift<rates_total-1 && !IsStopped(); shift++)
{
if(low[shift] <= low[shift+1])
{
if(Lowest(high,low,InpDepth-2,shift))
{
LowMapBuffer[shift] = low[shift];
}
else
{
LowMapBuffer[shift] = 0.0;
}
}
if(high[shift] >= high[shift+1])
{
if(Highest(high,low,InpDepth-2,shift))
{
HighMapBuffer[shift] = high[shift];
}
else
{
HighMapBuffer[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 ZigZag
for(shift=start; shift<rates_total && !IsStopped(); shift++)
{
res=0.0;
switch(extreme_search)
{
case Extremum:
if(last_low0.0 && last_high0.0)
{
if(HighMapBuffer[shift]!=0)
{
last_high=high[shift];
last_high_pos=shift;
extreme_search=Bottom;
ZigZagBuffer[shift]=last_high;
res=1;
}
if(LowMapBuffer[shift]!=0.0)
{
last_low=low[shift];
last_low_pos=shift;
extreme_search=Peak;
ZigZagBuffer[shift]=last_low;
res=1;
}
}
break;
case Peak:
if(LowMapBuffer[shift]!=0.0 && LowMapBuffer[shift]<last_low && HighMapBuffer[shift]==0.0)
{
ZigZagBuffer[last_low_pos]=0.0;
last_low_pos=shift;
last_low=LowMapBuffer[shift];
ZigZagBuffer[shift]=last_low;
res=1;
}
if(HighMapBuffer[shift]!=0.0 && LowMapBuffer[shift]==0.0)
{
last_high=HighMapBuffer[shift];
last_high_pos=shift;
ZigZagBuffer[shift]=last_high;
extreme_search=Bottom;
res=1;
}
break;
case Bottom:
if(HighMapBuffer[shift]!=0.0 && HighMapBuffer[shift]>last_high && LowMapBuffer[shift]==0.0)
{
ZigZagBuffer[last_high_pos]=0.0;
last_high_pos=shift;
last_high=HighMapBuffer[shift];
ZigZagBuffer[shift]=last_high;
}
if(LowMapBuffer[shift]!=0.0 && HighMapBuffer[shift]==0.0)
{
last_low=LowMapBuffer[shift];
last_low_pos=shift;
ZigZagBuffer[shift]=last_low;
extreme_search=Peak;
}
break;
default:
return(rates_total);
}
}
//— return value of prev_calculated for next call
return(rates_total);
}
//±-----------------------------------------------------------------+
//| looking for peak |
//±-----------------------------------------------------------------+
bool Highest(const double &hh[],const double &ll[],const int depth,const int start)
{
bool bb = false;
double llv = ll[start];
double hhv = hh[start];
int i = start-1;
while(i >= 0 && !bb)
{
if(hhv <= hh[i])
{
break;
}
else
{
if(start-i > depth && ll[i] <= llv)
{
bb = true;
break;
}
llv = llv <= ll[i] ? llv : ll[i];
}
i–;
}
return(bb);
}
//±-----------------------------------------------------------------+
//| looking for bottom |
//±-----------------------------------------------------------------+
bool Lowest(const double &hh[],const double &ll[],const int depth,const int start)
{
bool bb = false;
double llv = ll[start];
double hhv = hh[start];
int i = start-1;
while(i >= 0 && !bb)
{
if(llv >= ll[i])
{
break;
}
else
{
if(start-i > depth && hh[i] >= hhv)
{
bb = true;
break;
}
hhv = hhv >= hh[i] ? hhv : hh[i];
}
i–;
}
return(bb);
}
//±-----------------------------------------------------------------+