Creating a Reliable Highest High/ Lowest Low indicator (Tops and Bottoms)

 

the idea is simple, mabe it is not a smart way to do it.
The idea I had was using 2 iMAs to define whether it is a bullish or bearish trend, nothing special.
When both iMAs cross, they usually cross right after a new Highest High/ trend reversal, or they cross right after the price ranges.

Either way, the idea was using this cross point as an anchor for finding Tops or Bottoms, before x candles, search for the highest bar with iHighest or if the new trend is bearish, search for the lowest bar with iLowest,

the thing is: there is no way to find the index in wich the iMA cross occoured,I tryed creating an object when it occours but the object can only be created at the most recent iMA cross, it wont read the past like a ZigZag indicator would,
the reason I´m not using ZigZag or just an usual iHighest is because both of them are going to give results either before the trend changes, or too late.
if there was a way to find the iMA cross index and use this index as a limit+amount of bars   for iHighest I would be greateful, if there isnt a way, what is another solution?

 
just whenhigh:

the idea is simple, mabe it is not a smart way to do it.
The idea I had was using 2 iMAs to define whether it is a bullish or bearish trend, nothing special.
When both iMAs cross, they usually cross right after a new Highest High/ trend reversal, or they cross right after the price ranges.

Either way, the idea was using this cross point as an anchor for finding Tops or Bottoms, before x candles, search for the highest bar with iHighest or if the new trend is bearish, search for the lowest bar with iLowest,

the thing is: there is no way to find the index in wich the iMA cross occoured,I tryed creating an object when it occours but the object can only be created at the most recent iMA cross, it wont read the past like a ZigZag indicator would,
the reason I´m not using ZigZag or just an usual iHighest is because both of them are going to give results either before the trend changes, or too late.
if there was a way to find the iMA cross index and use this index as a limit+amount of bars for iHighest I would be greateful, if there isnt a way, what is another solution?

What do you mean by "there is no way to find the index in which the iMA cross occurred"?

That is the most basic of things in so many indicators and EAs for triggering alerts, entries and exits.

Search the CodeBase for any indicator with moving average cross, with alerts or buy/sell signals, and study their source code and then apply it to your own.

 

Try this , it is not a perfect "ZigZag" but i find the print very interesting . Theres comments in the code for how it does it 

Edit : Be very careful with the highs and lows , it does not repaint but remember each high and low is discovered at the time of the next ma cross to its right 

#property copyright "Copyright 2072, Boulevard of Mosquitto Bars."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window
#property indicator_buffers 6
#property indicator_plots   3
//--- plot fastMA
#property indicator_label1  "fastMA"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrRoyalBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot slowMA
#property indicator_label2  "slowMA"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrCrimson
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Zig
#property indicator_label3  "ZigZag"
#property indicator_type3   DRAW_SECTION
#property indicator_color3  clrOrange
#property indicator_style3  STYLE_SOLID
#property indicator_width3  2

input int fMAperiod=21;//FastMA Period
input ENUM_MA_METHOD fMAmethod=MODE_SMA;//FastMA Method
input int fMAshift=0;//FastMA Shift
input ENUM_APPLIED_PRICE fMAprice=PRICE_CLOSE;//FastMA Price
input int sMAperiod=71;//SlowMA Period
input ENUM_MA_METHOD sMAmethod=MODE_SMA;//SlowMA Method
input int sMAshift=0;//SlowMA Shift
input ENUM_APPLIED_PRICE sMAprice=PRICE_CLOSE;//SlowMA Price
input int maxEquals=2;//Max times equal prices are allowed before breach

//--- indicator buffers
double         fastMA[];
double         slowMA[];
double         ZigZag[];
/*
now we need some sort of distance memory pointing to the previous breach of the mas 
*/
double maBreachDistance[];//this has the distance to the breach 
/*
on the bar these crossed this is 0 , on the next one 1 etc if this is -1 we have no check for HL simply 
*/
//we also use a price carry
double previousFractalPrice[];//or -1.0 for none
//and a distance to the previous fractal in bars
double fractalDistance[];//or -1.0 for none
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int mirror=0;
int OnInit()
  {
  if(fMAperiod>=sMAperiod){Alert("Really dude?");return(INIT_FAILED);}
//--- indicator buffers mapping
   SetIndexBuffer(0,fastMA);
   SetIndexBuffer(1,slowMA);
   SetIndexBuffer(2,ZigZag);
   SetIndexBuffer(3,maBreachDistance);SetIndexStyle(3,DRAW_NONE,EMPTY,EMPTY,clrNONE);
   SetIndexBuffer(4,previousFractalPrice);SetIndexStyle(4,DRAW_NONE,EMPTY,EMPTY,clrNONE);
   SetIndexBuffer(5,fractalDistance);SetIndexStyle(5,DRAW_NONE,EMPTY,EMPTY,clrNONE);
   SetIndexEmptyValue(0,0.0);
   SetIndexEmptyValue(1,0.0);
   SetIndexEmptyValue(2,0.0);
   reset();
   mirror=(int)MathMax(fMAperiod+fMAshift,sMAperiod+sMAshift);
//---
   return(INIT_SUCCEEDED);
  }
  
void reset(){
ArrayFill(fastMA,0,ArraySize(fastMA),0.0);
ArrayFill(slowMA,0,ArraySize(slowMA),0.0);
ArrayFill(ZigZag,0,ArraySize(ZigZag),0.0);
ArrayFill(maBreachDistance,0,ArraySize(maBreachDistance),-1.0);
ArrayFill(previousFractalPrice,0,ArraySize(previousFractalPrice),-1.0);
ArrayFill(fractalDistance,0,ArraySize(fractalDistance),-1.0);
}
//+------------------------------------------------------------------+
//| 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[])
  {
//---
  int from=rates_total-prev_calculated-mirror-2;
  if(from<0){from=0;}
  //if interject data , scrap restart 
    if(from>100)
    {
    reset();
    from=rates_total-mirror-2;
    } 
  //loop to bars 
    for(int i=from;i>=1;i--)
    {
    //propagate breach distance if not -1 
      if(maBreachDistance[i+1]!=-1.0){maBreachDistance[i]=maBreachDistance[i+1]+1.0;}
    //propagate previous fractal price if not -1
      if(previousFractalPrice[i+1]!=-1.0){previousFractalPrice[i]=previousFractalPrice[i+1];}
    //propagate fractal distance if not -1
      if(fractalDistance[i+1]!=-1.0){fractalDistance[i]=fractalDistance[i+1]+1.0;}
    //mas
      fastMA[i]=iMA(_Symbol,_Period,fMAperiod,fMAshift,fMAmethod,fMAprice,i);
      slowMA[i]=iMA(_Symbol,_Period,sMAperiod,sMAshift,sMAmethod,sMAprice,i);
    //now check if there is a breach up or down on this point , keep in mind we are at the close of the bar
      bool breachUP,breachDW;
      if(find_cross(fastMA,slowMA,rates_total-mirror-2,i,breachUP,breachDW,maxEquals)){
      //if breach up or breach down it means we had a cross at i+1 with fast of i's being beyond slow of i's
        //breach up  
          if(breachUP){
          //is there a previous breach ? likely down 
            if(maBreachDistance[i]!=-1.0){
            //we have a breach down (previous) and a breach up (current) so we find the lowest 
            //price between these points
              int lowest_ix=-1;double lowest_price=0.0;
              if(find_lowest_between_points(Time[i+(int)(maBreachDistance[i])],Time[i],lowest_price,lowest_ix)){
              //if we have a previous fractal , likely a high we link it to the new low , a new Zag (:P)
                if(fractalDistance[i]!=-1.0){
                ZigZag[i+(int)(fractalDistance[i])]=previousFractalPrice[i];
                ZigZag[lowest_ix]=lowest_price;
                }
              //reset the distance and price of the latest fractal , we need it on the current slot so : 
                fractalDistance[i]=lowest_ix-i;
                previousFractalPrice[i]=lowest_price;
              }
            }
            //rest breach distance counter
          maBreachDistance[i]=1.0;//one after the breach point
          maBreachDistance[i+1]=0.0;//exact breach point
          }
        //breach down  
          else if(breachDW){
          //is there a previous breach ? likely up
            if(maBreachDistance[i]!=-1.0){
            //we have a breach up (previous) and a breach down (current) so we find the highest 
            //price between these points
              int highest_ix=-1;double highest_price=0.0;
              if(find_highest_between_points(Time[i+(int)(maBreachDistance[i])],Time[i],highest_price,highest_ix)){
              //if we have a previous fractal , likely a low we link it to the new high , a new Zig (:P)
                if(fractalDistance[i]!=-1.0){
                ZigZag[i+(int)(fractalDistance[i])]=previousFractalPrice[i];
                ZigZag[highest_ix]=highest_price;
                }
              //reset the distance and price of the latest fractal , we need it on the current slot so : 
                fractalDistance[i]=highest_ix-i;
                previousFractalPrice[i]=highest_price;
              }
            }
            //rest breach distance counter
          maBreachDistance[i]=1.0;//one after the breach point
          maBreachDistance[i+1]=0.0;//exact breach point          
          }
      }
    }
  //loop to bars ends here 
//--- return value of prev_calculated for next call
   return(rates_total);
  }
  
  
//function to find cross in series 
bool find_cross(double &fast_series[],//the fast ma buffer
                double &slow_series[],//the slow ma buffer
                int data_max,int i,//the max data slot and the current slot (of which we are on the CLOSE)
                bool &is_cross_above,//returns true if cross above
                bool &is_cross_below,//returns true if cross below 
                int maxequals){//max allowed equal values before breach
  is_cross_above=false;
  is_cross_below=false;
  //if fast is above slow we look for a recent breach up
    if(fast_series[i]>slow_series[i]){
    int equals=0;//we initiate a counter for equal values which we'll be checking against the maxequals
    int nav=i+1;//we setup a mini navigation with infinite loop potential we start from current bar +1 
    while(is_cross_above==false&&equals<=maxequals){//while we have not confirmed a cross above then 
         if(nav<data_max){//if we are within bar limits 
         if(fast_series[nav]==slow_series[nav]){equals++;nav++;}//if equal values , increase equals count and navigate left
         else if(fast_series[nav]<slow_series[nav]){//on confirmation of breach bounce
         is_cross_above=true;return(true);
         }else{return(true);//if still above , no interest , bounce
         }}
         else{return(false);}//if outside data max bounce
         }
    }
  //else if slow is above fast we look for a recent breach down 
    else if(fast_series[i]<slow_series[i]){
    int equals=0;//we initiate a counter for equal values which we'll be checking against the maxequals
    int nav=i+1;//we setup a mini navigation with infinite loop potential we start from current bar +1 
    while(is_cross_below==false&&equals<=maxequals){//while we have not confirmed a cross below then 
         if(nav<data_max){//if we are within bar limits 
         if(fast_series[nav]==slow_series[nav]){equals++;nav++;}//if equal values , increase equals count and navigate left
         else if(fast_series[nav]>slow_series[nav]){//on confirmation of breach bounce
         is_cross_below=true;return(true);
         }else{return(true);//if still below , no interest , bounce
         }}
         else{return(false);}//if outside data max bounce
         }
    }
    else if(fast_series[i]==slow_series[i]){return(true);}
return(false);
}

bool find_lowest_between_points(datetime earliest,datetime latest,double &lowest_price,int &lowest_ix){
bool found=false;
int errors=0;
ResetLastError();
int early_bar=iBarShift(_Symbol,_Period,earliest,true);errors+=GetLastError();
int late_bar=iBarShift(_Symbol,_Period,latest,true);errors+=GetLastError();
if(errors==0&&early_bar>=late_bar){
lowest_price=Low[early_bar];lowest_ix=early_bar;
for(int i=early_bar;i>=late_bar;i--)
  {
  if(Low[i]<lowest_price){lowest_price=Low[i];lowest_ix=i;}
  }
found=true;
}
return(found);
}
bool find_highest_between_points(datetime earliest,datetime latest,double &highest_price,int &highest_ix){
bool found=false;
int errors=0;
ResetLastError();
int early_bar=iBarShift(_Symbol,_Period,earliest,true);errors+=GetLastError();
int late_bar=iBarShift(_Symbol,_Period,latest,true);errors+=GetLastError();
if(errors==0&&early_bar>=late_bar){
highest_price=High[early_bar];highest_ix=early_bar;
for(int i=early_bar;i>=late_bar;i--)
  {
  if(High[i]>highest_price){highest_price=High[i];highest_ix=i;}
  }
found=true;
}
return(found);
}
Reason: