MQL4 iCustom returns always the same (wrong) value (0x7FFFFFFF)

0

I wrote a custom indicator Speed.mq4 as follows:

double         SpeedBuffer[];                     // a Custom Indicator BUFFER
int OnInit() {
    SetIndexBuffer( 0, SpeedBuffer );             // an access INDEX 0->BUFFER
    ...
    }
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 start;
   if (   prev_calculated == 0 ) start = 1;
   else                          start = prev_calculated - 1;

   for ( int i = start; i < rates_total - 1 ; i++ ) {                   // CPU-WASTED BY AN INEFFICIENT BACK-STEPPING IN TIME
         double curTypical  = typical( high[i],  low[i],  close[i]   );
         double prevTypical = typical( high[i+1],low[i+1],close[i+1] ); // CPU-WASTED, NO NEED TO RECALC ...
         double curSpeed    = curTypical - prevTypical;
         SpeedBuffer[i]     = curSpeed;
     }
//--- return value of prev_calculated for next call
   return( rates_total );
  }

The indicator works fine in the application and the chart is plotted correctly.

When I try retrieving the last value in the ExpertAdvisor I always receive the same value:

double speed = iCustom( NULL, 0, "Speed", 2, 0, 0 );
Print( "speed is: " + speed );

prints:

speed is: 2147483647

It's always the same number. I'm not sure where's the problem.

from the Print in the indicator I can see the values are calculated correctly. but when I use iCustom I receive only that value.

mql4
asked on Stack Overflow Oct 21, 2014 by Don Giulio • edited Apr 10, 2018 by Stanislav Kralin

3 Answers

2

MQL4 Custom Indicator iCustom() mechanics

MQL4 and even the New-MQL4 ( sometime called an MQL4.5 ) use a rather complicated interfacing model to handle Expert Advisor call / Custom Indicator computations.

A first thing to realise is, that iCustom() is not a call to a function, but rather a method, that indirectly "asks" a by-a-filename referred Custom Indicator to retrieve one, specific, value from a "pre-calculated" DataSTORE.

While it may sound complicated, it is the very nature of a CPU-efficient calculation factory, that the Custom Indicators were designed for in the early days of MQL4 world.

iCustom() is thus just a syntax-sugar to initiate the retrieval method, that gets the relevant piece of pre-calculated value back into the hands of Expert Advisor.

Custom Indicators put all the pre-calculated values into BUFFER(s), co-aligned with the TimeSeries style of ordering the DataSTORE cells ( [0] == "Now, the current Bar", going forwards [1], [2], [3], ... deeper and deeper back into the history )

The iCustom() passes the shift value, as a number of bars -- i.e. how deep into the history the retrieving method has to go, so as to pick the requested value from the respective BUFFER, and also the BUFFER identification INDEX ( 0 in our case above, as there is just a single BUFFER, with INDEX == 0 ). This is used for the sake of the EA being fully agnostic of the Custom Indicator internal variable names et al.

Just ask which BufferINDEX for which BarNUMBER one wants the value to be read from.

The Buffer is the one, who is to be blamed for the (wrong) value

The first line of the code says:

double         SpeedBuffer[];                     // a Custom Indicator BUFFER

If not handled otherwise in OnInit(){} all cells in the SpeedBuffer will have EMPTY_VALUE

Empty value in an indicator buffer has by default this value == 2147483647 (0x7FFFFFFF) as has been objected above.

Q.E.D.

One may state in OnInit(){ ArrayInitialize( SpeedBuffer, 0.123456 ); } to have any other value for a cell-initialisation ( that for a TimeSeries-alligned BUFFERs happens upon each new-Bar event ( all cells get reshuffled by one backwards & cell[0] becomes "empty", pre-loaded with a default value discussed here ) ).

One may also add a step in an indicator OnCalculate(){ ... SpeedBuffer[0] = -9.87654; ...} so as to avoid leaving the cell[0] in a context-inconsistent state, not in a "just"-initialised state / value.


Caller-side interface ( how to reduce a risk on a weak-integration interface )

Nevertheless, the responsibility of the value retrieval is on the Expert Advisor side, as it fills the parameters of the iCustom() interface-proxy.

One may use preventive steps as shown in >>> https://stackoverflow.com/a/26389823/3666197 to minimise a risk of improper parameters ordering / values once calling an external Custom Indicator(s) to retrieve a set of values.

This simple method may save you literally tens of man*days of testing/debugging once a rich-extern-parametrised Custom Indicator with several indicator buffers has fallen into suspects due to serving "wrong" numbers ( just due to iCustom() call parameters being "invisibly" out of proper order/context )

answered on Stack Overflow Oct 22, 2014 by user3666197 • edited May 23, 2017 by Community
1

Another thing to keep in mind when a custom indicator shows different values on the chart then are reported to the ExpertAdvisor, is that the execution flow through OnCalculate() needs to be different for an ExpertAdvisor than it is for a chart; specifically, the chart initially kicks off a call to OnCalculate() with prev_calculated = 0, whereas an EA (whether run with Strategy Tester or live) will always have prev_calculated = rates_total-1, so that the number of bars to compute the indicator value for is rates_total - prev_calcualted = 1 (ie. just the current bar).

You do account for this in your code, by setting start, but in general for a complicated indicator (that often involves referencing more than just the previous bar) one needs to be mindful of this difference and never assume that if the indicator looks good on the chart that means it's actually working. It needs to be tested separately with an EA.

answered on Stack Overflow Jan 27, 2018 by B Custer
0

I reviewed my code and finally figured that:

 double speed=iCustom(NULL,0,"Speed",2,0,0);

was using the last value, which was not yet calculated by the custom indicator,

changing it to:

 double speed=iCustom(NULL,0,"Speed",2,0,1);

did the trick.

answered on Stack Overflow Oct 21, 2014 by Don Giulio

User contributions licensed under CC BY-SA 3.0