Anyone know how to develop a multicurrency indicator ?

 
Anyone know how to develop a multicurrency indicator ?

I want to choose BETWEEN 1 to 10 different currencies and 5 bars for each currency.

 

But i don't know how to do this.

 

In a standard indicator, you would build the buffer arrays with data from the parameters sent via the OnCalulate( ... ) event function. But, for multi-currency and/or multi-time-frame, you will have to use one of two solutions:

  • Using the old method of the "iFunction" variations, such as iTime(), iVolume, iOpen, iClose, etc. but with a different symbol such as "EURUSD", "JPYUSD", etc. instead of the default _Symbol or Symbol().
  • Using the newer method of the first variant of ArrayCopyRates() function together with array pointers of MqlRates.  The "copied" arrays, will not actually take up any space and will just be pointers to the existing data of the various symbols and time-frames.

However, for this to work, one of two conditions have to exist for the multi-symbol and/or multi-time-frame to work:

  • Either the respective charts for the symbols and time-frames are already open, so that no error is generated,
  • or you will get an error 4066 (ERR_HISTORY_WILL_UPDATED) the first time you request the data, and you will have to code a sleep & retry loop, in order to wait for data to download and then request the data again.

My personal suggested solution, which I find as the most efficient as well as easiest way to handle the 4066 error, is the ArrayCopyRates() and MqlRates method.

There is more information about this the MQL4 documentation and help files.

PS! NB! When accessing built-in indicator functions, such as iMA(), iATR(), etc. for the various symbols and time-frames, remember to also implement the sleep and retry loops so as not to get the 4066 error either. Here is a quote from the MQL4 documentaion:

Any indicator can be calculated on the data of not only current chart, but also on the data of any available symbol/period. If data (symbol name and/or timeframe differ from the current ones) are requested from another chart, the situation is possible that the corresponding chart was not opened in the client terminal and the necessary data must be requested from the server. In this case, error ERR_HISTORY_WILL_UPDATED (4066 - the requested history data are under updating) will be placed in the last_error variable, and one will has to re-request (see example of ArrayCopySeries())
 
Remember, the OP is asking about an indicator. Sleep() is ignored in indicators
 
GumRai:
Remember, the OP is asking about an indicator. Sleep() is ignored in indicators

Sorry did not know that! I use this method quite extensively in EA's but not in Indicators, so did not know about the sleep handicap.

In that case, he will have to build a retry loop around successive calls on every tick call to the OnCalculate() function (where the use of ArrayCopyRates() is the better solution).

Alternatively, if it works in the OnInit() function, it might be the preferred method of preparing the data for the indicator, with a very long retry count (without the sleep) for this case.

 
FMIC:

...

  • or you will get an error 4066 (ERR_HISTORY_WILL_UPDATED) the first time you request the data, and you will have to code a sleep & retry loop, in order to wait for data to download and then request the data again.

PS! NB! When accessing built-in indicator functions, such as iMA(), iATR(), etc. for the various symbols and time-frames, remember to also implement the sleep and retry loops so as not to get the 4066 error either. Here is a quote from the MQL4 documentaion:


Unless they changed something recently, you'll get the 4066 error every time from the first function call (and only from this first call), regardless of conditions or history update progress. It has no practical use.
 
Ovo:
Unless they changed something recently, you'll get the 4066 error every time from the first function call (and only from this first call), regardless of conditions or history update progress. It has no practical use.
That has not been the case with me. When the data is already fully available, I do not get the 4066 error. However, if it is not directly available, then yes I get the error only on the first call of any function for that particular symbol and time.frame. After that any other function that requests that data, no longer gives the error.
 

FMIC:

In that case, he will have to build a retry loop around successive calls on every tick call to the OnCalculate() function (where the use of ArrayCopyRates() is the better solution).

Alternatively, if it works in the OnInit() function, it might be the preferred method of preparing the data for the indicator, with a very long retry count (without the sleep) for this case.

  1. A loop (long or otherwise) in the indicator will not work. While the indicator is running nothing else in the terminal can happen. That is why Sleep can't work in indictors. And why ArrayCopyRates is asynchronous (for indicators.)
  2. Enable the rates array in init. Test it in OnTick, and handle retries there. Also remember different charts create new bars at different times.
    string pairs[] = {"EURUSD", "GBPUSD" ...}
    MqlRates pair0[], pair1[], ...
    bool initial;
    OnInit(){ initial=true;
       ArrayCopyRates(pair0, pairs[0], _Period);   
       ArrayCopyRates(pair1, pairs[1], _Period);
       :
    }
    OnCalculate( ... ){
       int count = IndicatorCounted();
       if(initial){
          if(pair1[0].time == 0) return;
          if(pair2[0].time == 0) return;
          :
          initial=false; count = 0; // process all bars
       }
       for(int i = Bars - 1 - MathMax(lookback, count); i >= 0; --i){
          int shift0 = iBarsShift(pairs[0], _Period, Time[i]);
          int shift1 = iBarsShift(pairs[1], _Period, Time[i]);
          buffer[i] = pair0[shift0].close - pair1[shift1].close;

  3. If you don't want to use ArrayCopyRates you don't have to, but you must still load the other pairs by replacing [in the if(initial)] the pairN[0].time with iTime().
 
   if(pair1[0].time == 0) return;

This will never be true.

If there is any history loaded for the symbol and timeframe the function will retrieve the most recent value.

If there is no history loaded, you will get an Array out of range error.

Same with iTime etc

 
GumRai:

This will never be true.

If there is any history loaded for the symbol and timeframe the function will retrieve the most recent value.

If there is no history loaded, you will get an Array out of range error.

Same with iTime etc

I am inclined to agree!

Personally, I just check the return value of "ArrayCopyRates()" and after that I just keep track of the array size before accessing the array data.

With regards to "iTime()" and other such functions, I always check the "iBars()" first.

 
GumRai:

This will never be true.

  if(pair1[0].time == 0) return;

If there is any history loaded for the symbol and timeframe the function will retrieve the most recent value.

If there is no history loaded, you will get an Array out of range error.

Same with iTime etc

There are many historic (pre-build 600) examples of looking at a ACR. There is no other way to do it. Subsequent calls to ACR or iTime will NOT return 4066, so how can you possibly know wether the data has been downloaded.

iTime has always returned zero on an error.

 
WHRoeder:

There are many historic (pre-build 600) examples of looking at a ACR. There is no other way to do it. Subsequent calls to ACR or iTime will NOT return 4066, so how can you possibly know wether the data has been downloaded.

iTime has always returned zero on an error.

What do you mean by "there is no other way to do it"?

Checking the return count from "ArrayCopyRates", and checking the array size, seems to be a more robust method of checking, than doing "pair1[0].time == 0" which can easily return an "Array index is out of range" error.

EDIT: Removed some of my statements after re-reading your post more closely.

Reason: