OnCalculate() returned value and prev_calculated parameter

 

Referring to https://docs.mql4.com/basis/function/events, OnCalculate paragraph.

One can read:

We should noted the connection between the return value of OnCalculate() and the second input parameter prev_calculated. During the function call, the prev_calculated parameter contains a value returned by OnCalculate() during previous call. This allows for economical algorithms for calculating the custom indicator in order to avoid repeated calculations for those bars that haven't changed since the previous run of this function.

For this, it is usually enough to return the value of the rates_total parameter, which contains the number of bars in the current function call. If since the last call of OnCalculate() price data has changed (a deeper history downloaded or history blanks filled), the value of the input parameter prev_calculated will be set to zero by the terminal.

The assertion "... the prev_calculated parameter contains a value returned by OnCalculate() during previous call" turns out to be untrue.

This is obvious running the following code:

#property strict
#property indicator_separate_window
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   
//---
   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[])
  {

static int round;

round++;

//---
Alert("--------------  "+IntegerToString(round));

Alert("rates_total="+IntegerToString(rates_total));
Alert("prev_calculated="+IntegerToString(prev_calculated));

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


Whatever the returned value is, MT4 ignores it.

Actual logic is:

  • at first call, rates_total = Bars and prev_calculated = 0
  • at second call and for subsequent call until bar shift, both rates_total and prev_calculated equal Bars
  • at bar shift, rates_total = Bars and prev_calculated = Bars - 1
  • if more than 1 new bar arrives due to past bar update in the series or if the user refreshes the chart, rates_total = Bars and prev_calculated = 0

In other words:

  • MT4 doesn't take account of the OnCalculate returned value
  • MT4 manages rates_total and prev_calculated independently
  • The amount of most recent bars to process is : rates_total - prev_calculated. As a consequence, the whole series will be (re)calculated whenever prev_calculated = 0 which occurs at first call, at refresh or at history update.

The documentation obviously doesn't match the actual MT4 behavior.




 
Thanks for sharing your findings.
 

Yes there are some things MQ seems unwilling to rectify, that is one of them. It has been that way since the very first beta with OnCalculate.

Another one is the Indicator OnTimer event not working when the indicator is called via iCustom. When I told the service desk it isn't working they replied "yes it is" and closed the support ticket. I mean really, what does that tell you about the professionalism of the people MQ have working for them.

Anyway bearing that in mind I opened a new support ticket. This time I babied them by doing their job for them and providing them with a test indicator and an EA to call it which demonstrated the issue like you would to a non programmer. This time their response was,

"The custom indicator created by iCustom() does not get a chart and a timer events. You should add the indicator on a chart in order to allow this indicator to get such events."

I felt like writing them back and saying obviously the indicator will get the events if it is attached to a chart independently !! But that is not the point is it !! Indicators are supposed to perform the same way when called by iCustom so an EA can use it, and aside from that, to suggest a timed event cannot be replicated without a chart is nonsense.

But I decided I wasted enough of my time already trying to help them fix their product. If they want to take that attitude, F*** them. I got better things to do.