Help getting highest value from a calculated indicator

 

Hi,

I am trying to convert an indicator from MQL4 to MQL5. I am struggling with the last part of it, which collects the highest and lowest prior values.

This indicator is suppose to add and subtract the ATR to the high and low of each bar, and from a given lookback period select the largest or smallest, and display both lines This indicator is a variant of the Chandelier exit, called Chande-Kroll exit...

An MQL5 version exist, but it fails to do it correctly, as it does not select the prior highest and lowest values.


#property indicator_chart_window
#property indicator_buffers 2
#property indicator_plots   2
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed

//--- labels
#property indicator_label1  "Upper Donchian"
#property indicator_label2  "Lower Donchian"

//--- input parameter
input int  InpDonchianPeriod=20;    // period of the channel
input int  AtrPeriod=10;            // atr period
input double  AtrMultiplier = 3.0; // Atr multiplier

//--- indicator buffers
double    ExtUpBuffer[];
double    ExtDnBuffer[];
double UpperLine[];
double LowerLine[]; 
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- define buffers
   SetIndexBuffer(0, UpperLine);
   SetIndexBuffer(1, LowerLine);


   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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 the indicator has previously been calculated, start from the bar preceding the last one
   int start=prev_calculated-1;

//--- if this is the first calculation of the indicator, then move by InpDonchianPeriod bars form the beginning
   if(prev_calculated==0)
      start=InpDonchianPeriod+1;

//--- calculate levels for all bars in a loop
   for(int i=start; i<rates_total; i++)
     {
       if(i-2-InpDonchianPeriod <0 ) continue; // bypass start of indicator 
       double _atr = 0; for(int k=1; k<=AtrPeriod && (i-k-1)>=0; k++) _atr += MathMax(high[i-k],close[MathMax(i-k-1,0)])- MathMin(low[i-k],close[MathMax(i-k-1,0)]); _atr/=(double)AtrPeriod;
      
       double highest = high[ArrayMaximum(high,i-InpDonchianPeriod,InpDonchianPeriod)];
       double lowest  = low [ArrayMinimum(low ,i-InpDonchianPeriod,InpDonchianPeriod)]; 

      ExtUpBuffer[i]=highest-AtrMultiplier*_atr ;
      ExtDnBuffer[i]=lowest+AtrMultiplier*_atr ;
  /*    
      UpperLine[i]=-10000000;
      LowerLine[i]= 10000000;
//----

      for(int ii=prev_calculated-InpDonchianPeriod-1;ii<rates_total;ii++)
        {
         UpperLine[i]=MathMax( UpperLine[i], ExtDnBuffer[ii+i]);
         LowerLine[i]=MathMin( LowerLine[i], ExtUpBuffer[ii+i]);
        } 
 */       
     }

//--- succesfully calculated
   return(rates_total);
  }

Chande Kroll Stop_v1
Chande Kroll Stop_v1
  • www.mql5.com
Chande Kroll Stop_v1 indicator.
 
Camilo Mora: . I am struggling with the last part of it, which collects the highest and lowest prior values.
Your loop is wrong. You already used ArrayMaximum before. Use it again on your buffer.
 
I believe that high level primitive functions such as ArrayMaximum should not be used. It's easier and faster to write your own function than to dig through the documentation and try to make ArrayMaximum work without knowing what's under the hood. Find the values you need in the loop yourself. Writing your own loop/function for this is not at all difficult or time-consuming. But in return you will be in control of everything.
 

I corrected the error in the  loop...


//+------------------------------------------------------------------
#property copyright   "mladen"
#property link        "mladenfx@gmail.com"
#property link        "https://www.mql5.com"
#property description "Chandelier exit"
//+------------------------------------------------------------------
#property indicator_chart_window
#property indicator_buffers 4
#property indicator_plots   4
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrDeepSkyBlue
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrPaleVioletRed


//--- input parameters

input int     AtrPeriod      =  10; // Atr period
input double  AtrMultiplier1 =  3.0; // Atr multiplier
input int     LookBackPeriod =  20; // Look-back period

double UplBuffer1[],UpdBuffer1[],DnlBuffer1[],DndBuffer1[];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,UplBuffer1,INDICATOR_DATA);
   SetIndexBuffer(1,DnlBuffer1,INDICATOR_DATA);
   SetIndexBuffer(2,UpdBuffer1,INDICATOR_DATA); 
   SetIndexBuffer(3,DndBuffer1,INDICATOR_DATA); 
   return (INIT_SUCCEEDED);
  }
//
//
//
void OnDeinit(const int reason)
  {
  }


//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
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(Bars(_Symbol,_Period)<rates_total) return(prev_calculated);
   if(ArrayRange(work,0)!=rates_total) ArrayResize(work,rates_total);

   int i=(int)MathMax(prev_calculated-1,1); for(; i<rates_total && !_StopFlag; i++)
     {
      int  _start = MathMax(i-LookBackPeriod,0);
      double _atr = 0; for(int k=1; k<=AtrPeriod && (i-k-1)>=0; k++) _atr += MathMax(high[i-k],close[MathMax(i-k-1,0)])- MathMin(low[i-k],close[MathMax(i-k-1,0)]); _atr/=(double)AtrPeriod;
      double _max = high[ArrayMaximum(high,_start,LookBackPeriod)];
      double _min = low [ArrayMinimum(low ,_start,LookBackPeriod)];

      UplBuffer1[i]    = _max-AtrMultiplier1*_atr;
      DnlBuffer1[i]    = _min+AtrMultiplier1*_atr;
     
     }
   return (i);
  }
//+------------------------------------------------------------------+