iHighest() in Indicator that searches for highest value

 

Hi all,

I am trying to write an indicator that will find the highest open price of the past x candles. Being playing with it for some time now but I still can’t figure out what is wrong.

The iHighest function I am using seems to not take the current bar into account in other situations it seems not to be finding the highest value and at other candles it works fine.  Probably there are other ways to go, use arrays instead of iHighest , I just need to understand why this code doesn’t work so I can grasp mql5 coding better . Have added several printing statements to help my find the error but still nothing.

Any help much appreciated

Thanks Leonidas

//+------------------------------------------------------------------+
//|                                                   testLLVHHV.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1 

#property indicator_plots  1

#property indicator_label1  "hhv"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+


input int hhvPeriod=3; //HHV Period

double hhvArray[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,hhvArray,INDICATOR_DATA);
   //ArraySetAsSeries(hhvArray,true);
   Print("Is the Array set as time series: "+IntegerToString(ArrayGetAsSeries(hhvArray)));
  //SetIndexBuffer(1,llvArray,INDICATOR_DATA);

//---
   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[])
  {
//---
   Print("Starting at: "+TimeToString(TimeTradeServer()));
   Print("Number of bars are: "+ IntegerToString(iBars(NULL,0)));
   Print("Checking again if the Array set as time series: "+IntegerToString(ArrayGetAsSeries(hhvArray)));
   
   
   static int nofLoop=0;
   int loopValue=rates_total-prev_calculated; // Total number of bars - previous number of bars calculated  Values  in the Array start from 0 and end at rates_total -1.     
   if(prev_calculated==0)loopValue--; // We calibrate here

   Print(" The loopValue is: "+IntegerToString(loopValue));


   for(int i=loopValue;i>=0;i--) 
     {
      Print("i value is: "+IntegerToString(i));

           hhvArray[i]=NormalizeDouble(open[iHighest(NULL,0,MODE_OPEN,hhvPeriod,i-hhvPeriod)],5);
 

         Print("The loop value is: "+IntegerToString(loopValue)+" The candle is: "+IntegerToString(i)+"With Open Price: "+DoubleToString(open[i])+" And the highest candle back three places back is: "+IntegerToString(iHighest(NULL,0,MODE_OPEN,hhvPeriod,i-hhvPeriod))+"With open price: "+DoubleToString(open[iHighest(NULL,0,MODE_OPEN,hhvPeriod,i-hhvPeriod)]));
      
      if (i - hhvPeriod <0) //No more candles to look back then continue. We are at the very beginning of the history we don't really care for it anywa
        {
        break;
      
        }
     }
   nofLoop++;
   Print("Time now "+TimeToString(TimeTradeServer()));
   Print("End of "+IntegerToString(nofLoop)+" iteration =====================================================");
   Sleep(10000);


//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
 
leon321: The iHighest function I am using seems to not take the current bar into account
iHighest(NULL,0,MODE_OPEN,hhvPeriod,i-hhvPeriod)
  1. Why did you post your MT4 question in the Root / MT5 Indicators section instead of the MQL4 section, (bottom of the Root page?)
              General rules and best pratices of the Forum. - General - MQL5 programming forum
    Next time post in the correct place. The moderators will likely move this thread there soon.

  2. Because that is what you coded. From your starting point (i-hhvPeriod) for hhvPeriod bars are bars [i-hvvPeriod*2-1 … i-hhvPeriod] bars (inclusive.) Don't you want to look at [i-hvvPeriod-1 … i] (hvvPeriod bars?)

 
William Roeder:
  1. Why did you post your MT4 question in the Root / MT5 Indicators section instead of the MQL4 section, (bottom of the Root page?)
              General rules and best pratices of the Forum. - General - MQL5 programming forum
    Next time post in the correct place. The moderators will likely move this thread there soon.

  2. Because that is what you coded. From your starting point (i-hhvPeriod) for hhvPeriod bars are bars [i-hvvPeriod*2-1 … i-hhvPeriod] bars (inclusive.) Don't you want to look at [i-hvvPeriod-1 … i] (hvvPeriod bars?)

     Hi William,

     Thank you for taking the time!

  1.  This is an MT5 Indicator question. My impression is it is posted in the right place.
  2.  I see what you mean you are right. Yea i want to look exactly hvvPeriod bars. Though this doesn't explain the different inconsistencies, if it was just a counting error i should have the same problem at every bar,also i shouldn't be getting any correct results (since it is checking at a different range).  Let me try again fixing the code with your update. I ll come back.
 
leon321 This is an MT5 Indicator question. My impression is it is posted in the right place.
My apologies
  1. I don't see any iHighest in the MT5 documentation.
              List of MQL5 Functions - Reference on algorithmic/automated trading language for MetaTrader 5

  2. And forgot iHighest was added last year.
              New MetaTrader 5 Platform beta build 1845: MQL5 functions for operations with bars and Strategy Tester improvements - Options Trading Strategies - General - MQL5 programming forum № 3 2018.06.08
 

I changed the code abit. Looped up instead of down and modified the math accordingly. I am still getting inconsistent results. Others candles the algorithm is     successful in finding the  correct value other candles it just doesn't.

I created a script with iHighest() to test the last twenty candles of the EUR/USD (Monthly Chart). The Script does get the values correct. My indicator not always.

From the latest to the newest candle my indicator got some of the candles correct some not. I can't find a pattern.

19     18     17      16      15      14      13     12      11     10     9       8      7      6      5      4     3       2         1    0

Err     Err    Err      Err     Err    Ok      Ok     Ok    error  ok    ok     ok    ok   ok   error   ok    error error  ok    ok

Indicator:

//+------------------------------------------------------------------+
//|                                                   testLLVHHV.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1 

#property indicator_plots  1

#property indicator_label1  "hhv"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2


//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+


input int hhvPeriod=3; //HHV Period

double hhvArray[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,hhvArray,INDICATOR_DATA);
   //ArraySetAsSeries(hhvArray,true);
   Print("Is the Array set as time series: "+IntegerToString(ArrayGetAsSeries(hhvArray)));
  //SetIndexBuffer(1,llvArray,INDICATOR_DATA);

//---
   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[])
  {
//---
   Print("Starting at: "+TimeToString(TimeTradeServer()));
   Print("Number of bars are: "+ IntegerToString(iBars(NULL,0)));
   Print("Checking again if the Array set as time series: "+IntegerToString(ArrayGetAsSeries(hhvArray)));
   
   
   static int nofLoop=0;
   int loopValue=rates_total-prev_calculated; // Total number of bars - previous number of bars calculated  Values  in the Array start from 0 and end at rates_total -1.     
   if(prev_calculated==0)loopValue--; // We calibrate here

   Print(" The loopValue is: "+IntegerToString(loopValue));


   for(int i=0;i<=loopValue;i++) 
     {
      Print("i value is: "+IntegerToString(i));

              if (i - hhvPeriod <0) 
       {
        continue;
       }


           hhvArray[i]=NormalizeDouble(open[iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i-hhvPeriod)],5);
 
 

         Print("The loop value is: "+IntegerToString(loopValue)+" The candle is: "+IntegerToString(i)+"With Open Price: "+DoubleToString(open[i])+" And the highest candle back three places back is: "+IntegerToString(iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i-hhvPeriod))+"With open price: "+DoubleToString(open[iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i-hhvPeriod)]));
      

     }
   nofLoop++;
   Print("Time now "+TimeToString(TimeTradeServer()));
   Print("End of "+IntegerToString(nofLoop)+" iteration =====================================================");
   Sleep(10000);


//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+


Script:

//+------------------------------------------------------------------+
//|                                                    TestIhigh.mq5 |
//|                        Copyright 2019, MetaQuotes Software Corp. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   for (int i=0;i<20;i++)
   {
   Print ("New Candle=================================  "+i);
   Print("We are calling iHighest with NULL,0,4,i");
   Print("The Index of the Highest Value is:"+IntegerToString(iHighest(NULL,0,MODE_OPEN,4,i)));
   Print("The Value of that bar is" + DoubleToString(iOpen(NULL,0,iHighest( NULL,0,MODE_OPEN,4,i))));
   }
  }  
//+------------------------------------------------------------------+

Any more advice you have more than welcome

 

iHighest

Return Value

The index of the highest value found on the corresponding chart (shift relative to the current bar) or -1 in case of an error. For error details, call the GetLastError() function.

Looks like you need to flip the array

#ifdef __MQL5__
   ArraySetAsSeries(open,true);
#endif
 

And this 

   ArraySetAsSeries(hhvArray,true);

too.

 
leon321: I am still getting inconsistent results. The Script does get the values correct. My indicator not always.
  1. int loopValue=rates_total-prev_calculated; 
    if(prev_calculated==0)loopValue--; // We calibrate here
    for(int i=0;i<=loopValue;i++){
       if (i - hhvPeriod <0) continue;
    The decrement can be avoided when you do your lookbacks correctly.

  2. You want to process bars [i … loopValue-hhvPeriod] Your test is wrong. Remove it and fix loopValue per № 1

  3. iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i-hhvPeriod)
    You completely ignored what I said in #1 № 2. What part of "Don't you want to look at [i-hvvPeriod-1 … i]" was unclear? Stop trying to look at the future.

  4. iHighest( NULL,0,MODE_OPEN,4,i)
    You script doesn't look at the future, only the past. Why does it surprise you when "Script does get the values correct. My indicator not always"?
 

William Roeder: he is asked by the script iOpen

   Print("The Value of that bar is" + DoubleToString(iOpen(NULL,0,iHighest( NULL,0,MODE_OPEN,4,i))));
whose bars are from zero. And in the indicator in MQL5 countdown. Already here the difference is clear.
 

Forum on trading, automated trading systems and testing trading strategies

iHighest() in Indicator that searches for highest value

Konstantin Nikitin, 2019.05.12 23:17

iHighest

Return Value

The index of the highest value found on the corresponding chart (shift relative to the current bar) or -1 in case of an error. For error details, call the GetLastError() function.

Looks like you need to flip the array

#ifdef __MQL5__
   ArraySetAsSeries(open,true);
#endif

Absolutely to the point! It would have never crossed my mind that all the Arrays open[], close[] are not a Timeseries,it just never registered in my brain all this time. I am transitioning from mql4 and i believe that was one key think i was missing. Went back to mql4 and checked that by default all the Arrays are in Timeseries while in mql5 they are not by default! Thanks Konstantin!!!

Yea did all Arrays Timeseries and now it very easy for me to work.Thanks Seng Joo


Is this  standard practice in MQL5 for similar indicators to convert to Timeseries or i am just taking an MQL4 path that i know and not being efficient?

Forum on trading, automated trading systems and testing trading strategies

iHighest() in Indicator that searches for highest value

William Roeder, 2019.05.13 14:16

  1. int loopValue=rates_total-prev_calculated; 
    if(prev_calculated==0)loopValue--; // We calibrate here
    for(int i=0;i<=loopValue;i++){
       if (i - hhvPeriod <0) continue;
    The decrement can be avoided when you do your lookbacks correctly.

  2. You want to process bars [i … loopValue-hhvPeriod] Your test is wrong. Remove it and fix loopValue per № 1

  3. iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i-hhvPeriod)
    You completely ignored what I said in #1 № 2. What part of "Don't you want to look at [i-hvvPeriod-1 … i]" was unclear? Stop trying to look at the future.

  4. iHighest( NULL,0,MODE_OPEN,4,i)
    You script doesn't look at the future, only the past. Why does it surprise you when "Script does get the values correct. My indicator not always"?


1,2. Awesome, i ll go back and fix everything to be more efficient!

3.But all means i didn't ignore. It just didn't cross my mind that i was looking at the future, though i still haven't understood 100% why that piece of code would be looking at the future before i  set open as a Timeseries Array.

If i understand correctly then iHighest will be looking at the open[] Array given my MODE_OPEN Directive. If the open[] Array is a standard ArrayNotSeries and the array is filed in the following fashion from 0....i like [0][1]....[i] (with 0 having the open price of the first candle  and "i" having the very last) then by looking at i-hvvPeriod i should be looking at the past and not the future correct?  Thanks William

For anyone's future reference this is the code that is currently working. As  William pointed out it is far from perfect  but at least it will allow for a complete understanding of my problem the very helpful answers and a solution (albeit an ugly one).


//+------------------------------------------------------------------+
//|                                                   testLLVHHV.mq5 |
//|                                                                  |
//|                                                                  |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, MetaQuotes Software Corp."
#property link      "https://www.mql5.com"
#property version   "1.00"
#property indicator_chart_window
#property indicator_buffers 1 

#property indicator_plots  1

#property indicator_label1  "hhv"
#property indicator_type1   DRAW_LINE
#property indicator_color1  clrBlue
#property indicator_style1  STYLE_SOLID
#property indicator_width1  2



//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+


input int hhvPeriod=3; //HHV Period it will look in total of three candles back in addition to current candle.

double hhvArray[];

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   Print("Time now "+TimeToString(TimeTradeServer()));
   //Print("Loading indicator "+ INDICATOR_SHORTNAME);
   //MqlParam
   SetIndexBuffer(0,hhvArray,INDICATOR_DATA);
   ArraySetAsSeries(hhvArray,true);  //We will set all Arrays as Timeseries. Last values will be stored in index 0

//---
   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[])
  {
//---
  

   #ifdef __MQL5__
       ArraySetAsSeries(open,true); // By default all the OnCalculate used tables are not TimeSeries. Thanks to Konstantin for pointing out.
   #endif
   

   static int nofLoop=0;
   int loopValue=rates_total-prev_calculated; // Total number of bars - previous number of bars calculated .Values  in the Arrays start from 0 and end at rates_total -1.     
   if(prev_calculated==0)loopValue--; // We calibrate here


   for(int i=loopValue;i>=0;i--) 
     {

       if ( nofLoop==0 && (loopValue-hhvPeriod)<i) 
       {
        Print("These are the very first bars, there is not enough history to calculate the hhv. This normal at the first bars");

        continue;
       }
            
  
        hhvArray[i]=NormalizeDouble(open[iHighest(NULL,0,MODE_OPEN,hhvPeriod+1,i)],5); //Find the index on the Array that holds the highest value between the elements [current candle -- hhvPeriod+1 ].
                                                                                       // Take the open price of the above discovered index and print it. Basically put it on the hhvArray or the buffer

     }
   nofLoop++;

   return(rates_total);
  }
//+------------------------------------------------------------------+
 
Completely to the point! It would have never entered my thoughts that all the Arrays open[], close[] are not a Timeseries,it just never enlisted in my mind this time. I am progressing from mql4 and I trust that was one key think I was absent. Returned to mql4 and watched that as a matter of course all the Arrays are in Timeseries while in mql5 they are not of course! Much obliged Konstantin!!!
Reason: