What the Lowest and Highest functions return

 
Dear Metatrader developers!

What do the Lowest and Highest functions return?
Why do I ask such a question? The description of these functions is confusing. When analyzing why ZigZag included into MetaTrader does not work correctly, I faced the fact that it is unclear what the above functions return. Or maybe because of the confusing description they are being misapplied? I described this problem on this forum page 77 in "Trading strategy based on Elliot's wave theory" section. I am trying to understand, maybe ZigZag algorithm is wrong. But it all depends on how these functions work.

I have also observed problems with these functions in other indicators. But at the moment it's in ZigZag.

Please clarify.
 
They return the number of the bar which is the highest and the lowest over N bars from the current bar to the back of the history. In this case, if two values are equal (two bars are extremums on this sample), the number of the bar that came earlier (is older) is always returned.

The Zigzag algorithm (included in MT4 as standard) does not take into account the situation when one bar can be both a maximum and a minimum at the same time (an outer bar).
 
Rosh, that's understandable. Try inserting those lines I gave in the wave analysis thread into the zigzag text. And see what you get. And you get rubbish. This is why the question arose.

Everything is clear with theory until it begins to diverge from practice. If mistakes occur, you must go all the way to the end. And find out where the mistakes are coming from.
 
Rosh, that's understandable. Try inserting those lines I gave in the wave analysis thread into the zigzag text. And see what you get. And you get rubbish. This is why I have asked you this question. <br / translate="no">


I looked at that page on onyx and opened the standard Zigzag to compare. The codes are different, you need to find your variant of Zigzag, take it apart thoroughly and only then you can say something. That's why I can't answer.

But yes, there are some differences in value recording in the code, which is shown on your page, but maybe it should be like that, it's hard to say. I have been doing such indicators with crawl values, it looks like a channel, but at least it doesn't lie on history.
 
Rosh, here is the zigzag code from codebase.mql.com

//+------------------------------------------------------------------+
//| Custom Moving Average.mq4 |
//| Copyright © 2005, MetaQuotes Software Corp.
//| https://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link "https://www.metaquotes.net/

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- indicator parameters
extern intDepth=12;
extern inttern ExtDeviation=5;
extern inttern ExtBackstep=3;
//---- indicator buffers
double ExtMapBuffer[];
double ExtMapBuffer2[];

//+------------------------------------------------------------------+
//| Custom indicator initialisation function |
//+------------------------------------------------------------------+
int init()
{
IndicatorBuffers(2);
//---- drawing settings
SetIndexStyle(0,DRAW_SECTION);
//---- indicator buffers mapping
SetIndexBuffer(0,ExtMapBuffer);
SetIndexBuffer(1,ExtMapBuffer2);
SetIndexEmptyValue(0,0.0);
//---- indicator short name
IndicatorShortName("ZigZag("+ExtDepth+", "+ExtDeviation+", "+ExtBackstep+")");
//---- initialization done
return(0);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int start()
{
int shift,back,lasthighpos,lastlowpos;
double val,res;
double curlow,curhigh,lasthigh,lastlow;

for(shift=Bars-ExtDepth; shift>=0; shift--)
{
val=Low[Lowest(NULL,0,MODE_LOW,ExtDepth,shift)];
if(val==lastlow) val=0.0;
else
{
lastlow=val;
if((Low[shift]-val)>(ExtDeviation*Point)) val=0.0;
else
{
for(back=1; back<=ExtBackstep; back++)
{
res=ExtMapBuffer[shift+back];
if((res!=0)&&(res>val)) ExtMapBuffer[shift+back]=0.0;
}
}
}
****** ExtMapBuffer[shift]=val;
//--- high
val=High[Highest(NULL,0,MODE_HIGH,ExtDepth,shift)];
if(val==lasthigh) val=0.0;
else
{
lasthigh=val;
if((val-High[shift])>(ExtDeviation*Point)) val=0.0;
else
{
for(back=1; back<=ExtBackstep; back++)
{
res=ExtMapBuffer2[shift+back];
if((res!=0)&&(res<val)) ExtMapBuffer2[shift+back]=0.0;
}
}
}
***** ExtMapBuffer2[shift]=val;
}


============================

The asterisks indicate places I cited on page 77 of my branch on wave analysis. How is this code different from the one I cited? This is a standard code.

Now I cite your words from the second post of this thread

Rosh 18.10.06 10:14

It returns the number of the bar, which is the highest and the lowest within N bars from the current one in the depth of the history. In doing so, if two values are equal (two bars are extrema on that sample), they always return the number of the bar that came first (is the oldest).

The Zigzag algorithm (included in MT4 as standard) does not take into account the situation when one bar can be a maximum and a minimum at the same time (outer bar).
======================
There is a line in the code: val=High[Highest(NULL,0,MODE_HIGH,ExtDepth,shift)];
The square brackets contain the bar number... well your answer says what this bar number is

Then in the line: ExtMapBuffer[shift]=val; - what do we have? Do we need to explain further?

First, the index of the indicator buffer must be equal to the index of the bar, from which we take the val value. Otherwise, there will be a discrepancy. What we actually have, when we see that the zigzag has a break in the air.

Rosh, don't get sidetracked. Your brainchild is a zigzag. Let's get to the bottom of this. There are a lot of errors in the code. If you carefully parse what I write, you will see obvious errors.

But that's not the main thing either. If it were only about these errors, I would not have asked the question, which is the title of this thread.
 
Again about the Lowest and Highest functions.

In the previous post I wrote about an error in the zigzag code.

The main error.

In a stretch of ExtDepth bars the bar with the highest high or lowest low is searched for. The search is performed from the SHIFT bar. Roche gave the following function definition: it returns the number of the bar highest and lowest within N bars of the current bar in the history section. But there is no definition of what the current bar is. The current bar is a zero bar or a bar with shift number. Judging by the given code of the zigzag, the current bar should be understood as a bar with shift number.

Suppose we have found the bar number in the ExtDepth section of the bars, counting from the bar with shift number. And that bar would not necessarily have a shift number. But the value of the extremum of the bar we have found that differs from the bar with the shift number is placed into the indicator buffer with the shift number: ExtMapBuffer[shift]=val. From here we get breaks in the zigzag hanging in the air. Everyone who tried to work with zigzag from MT has seen it.

This is a major mistake. But this mistake is easy to correct. And it was not worth bringing it up.

When one starts to clear this error, one will ask: on the bar with what number the Lowest and Highest functions found the extremum we are looking for? No logic helps here. No matter how hard I tried to figure out the number of this bar, it did not work.

That is why the question was addressed to the developers.

But I was glad that the question was answered by Rosh. It is after his edits that we have been using the zigzag included with MT for a long time.

Dear developers, please pay attention to the questions posed. The questions are serious. Many indicators use the zigzag that is included in the MT. I cannot count the number of complaints about the work of the zigzag.
I have given a description of errors. To a good extent, errors must be corrected. Ignoring error correction damages the company's reputation. And that is not good. No one wants that.
 
...the question arises, on which bar the Lowest and Highest functions found the extremum we are looking for? No logic helps here. No matter how hard I tried to calculate the number of the bar, it did not work.
In theory, index of the bar = Highest(NULL,0,MODE_HIGH,ExtDepth,shift)

I.e. it should be ExtMapBuffer2[Highest(NULL,0,MODE_HIGH,ExtDepth,shift)]=val;
 
nen, now I looked into standard Zig-Zag algorithm - there is another algorithm, different from what you gave:

//+------------------------------------------------------------------+
//|                                                       ZigZag.mq4 |
//|                      Copyright © 2005, MetaQuotes Software Corp. |
//|                                       http://www.metaquotes.net/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2005, MetaQuotes Software Corp."
#property link      "http://www.metaquotes.net/"

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_color1 Red
//---- indicator parameters
extern int ExtDepth=12;
extern int ExtDeviation=5;
extern int ExtBackstep=3;
//---- indicator buffers
double ExtMapBuffer[];
double ExtLowBuffer[];
double ExtHighBuffer[];

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   IndicatorBuffers(3);
//---- drawing settings
   SetIndexStyle(0,DRAW_SECTION);
//---- indicator buffers mapping
   SetIndexBuffer(0,ExtMapBuffer);
   SetIndexBuffer(1,ExtLowBuffer);
   SetIndexBuffer(2,ExtHighBuffer);
   SetIndexEmptyValue(0,0.0);
//---- indicator short name
   IndicatorShortName("ZigZag("+ExtDepth+","+ExtDeviation+","+ExtBackstep+")");
//---- initialization done
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int start()
  {
   int    shift, back,lasthighpos,lastlowpos,index;
   double val,res;
   double curlow,curhigh,lasthigh,lastlow;
//----
   for(shift=Bars-ExtDepth; shift>=0; shift--)
     {
      index=Lowest(NULL,0,MODE_LOW,ExtDepth,shift);
      val=Low[index];
      if(val==lastlow) val=0.0;
      else 
        { 
         lastlow=val; 
         if((Low[shift]-val)>(ExtDeviation*Point)) val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=ExtLowBuffer[shift+back];
               if((res!=0)&&(res>val)) ExtLowBuffer[shift+back]=0.0; 
              }
           }
        } 
      ExtLowBuffer[shift]=0.0;
      if(val!=0.0) ExtLowBuffer[index]=val;
      //--- high
      index=Highest(NULL,0,MODE_HIGH,ExtDepth,shift);
      val=High[index];
      if(val==lasthigh) val=0.0;
      else 
        {
         lasthigh=val;
         if((val-High[shift])>(ExtDeviation*Point)) val=0.0;
         else
           {
            for(back=1; back<=ExtBackstep; back++)
              {
               res=ExtHighBuffer[shift+back];
               if((res!=0)&&(res<val)) ExtHighBuffer[shift+back]=0.0; 
              } 
           }
        }
      ExtHighBuffer[shift]=0.0;
      if(val!=0.0) ExtHighBuffer[index]=val;
     }
//---- final cutting 
   lasthigh=-1; lasthighpos=-1;
   lastlow=-1;  lastlowpos=-1;

   for(shift=Bars-ExtDepth; shift>=0; shift--)
     {
      curlow=ExtLowBuffer[shift];
      curhigh=ExtHighBuffer[shift];
      if(curlow==0 && curhigh==0) continue;
      //---
      if(curhigh!=0)
        {
         if(lasthigh>0) 
           {
            if(lasthigh<curhigh) ExtHighBuffer[lasthighpos]=0;
            else ExtHighBuffer[shift]=0;
           }
         //---
         if(lasthigh<curhigh || lasthigh<0)
           {
            lasthigh=curhigh;
            lasthighpos=shift;
           }
         lastlow=-1;
        }
      //----
      if(curlow!=0)
        {
         if(lastlow>0)
           {
            if(lastlow>curlow) ExtLowBuffer[lastlowpos]=0;
            else ExtLowBuffer[shift]=0;
           }
         //---
         if((curlow<lastlow)||(lastlow<0))
           {
            lastlow=curlow;
            lastlowpos=shift;
           } 
         lasthigh=-1;
        }
     }
//---- merge 2 buffers
   lasthighpos=-1;
   lastlowpos=-1;
   for(shift=Bars-1; shift>=0; shift--)
     {
      if(shift>=Bars-ExtDepth) ExtMapBuffer[shift]=0.0;
      else
        {
         curlow=ExtLowBuffer[shift];
         curhigh=ExtHighBuffer[shift];
         //----
         res=0;
         if(curlow!=0)
           {
            if(lastlowpos==-1)
              {
               res=curlow;
               lastlowpos=shift;
              }
            else
              {
               if(lasthighpos!=-1 && lastlowpos>lasthighpos)
                 {
                  res=curlow;
                  lastlowpos=shift;
                 }
              }
           }
         if(curhigh!=0)
           {
            if(lasthighpos==-1)
              {
               res=curhigh;
               lasthighpos=shift;
              }
            else
              {
               if(lastlowpos!=-1 && lasthighpos>lastlowpos)
                 {
                  res=curhigh;
                  lasthighpos=shift;
                 }
              }
           }
         //----
         ExtMapBuffer[shift]=res;
        }
     }
  }
//+------------------------------------------------------------------+



Everything seems to be correct here - both the index is saved and the value is written to the desired array element. Let's start from this algorithm.

 
nen, excuse me, but wouldn't it be easier to write a short code that finds these Lowest and Highest? I have simply never used these functions, precisely because I obtain the data I need for extrema by a simple short code, for it will certainly work faster than the standard functions. It seems to me that they make sense to use them only when it is necessary to obtain data from another timeframe.
 
komposter, that's right. Then look where it is written to. In the indicator buffer with which index.
Vladislav, the code is from codebase.mql.com and it is exactly the same. I will try to put your code. I will see what may happen.
Candid, I agree that it may be simpler. But I will need these functions to work with another timeframe.
Reason: