Help: array out of range, though in do...while loop I have tried to check error and exit

 

Dear Fellows

I am getting frequent '2024.01.21 16:20:11.328 iSessionVP v1.99 (XAUUSD,M15) array out of range in 'SessionVPHisto.mqh' (258,23) error.

        //+---------------------------------------------------------------------------------------------------------------------------+
        //| We obtain the data from 'timeSessionStart' to 'timeSessionEnd' for each array, and copied bars should be equal in each array
        //+---------------------------------------------------------------------------------------------------------------------------+
                int err = 0;
                do{
                        copiedTime  = CopyTime(mSymbol,PERIOD_M1,timeSessionStart,timeSessionEnd,Time);
                        copiedVol   = CopyTickVolume(mSymbol,PERIOD_M1,timeSessionStart,timeSessionEnd,Volume);
                        copiedHigh  = CopyHigh(mSymbol,PERIOD_M1,timeSessionStart,timeSessionEnd,High);
                        copiedLow   = CopyLow(mSymbol,PERIOD_M1,timeSessionStart,timeSessionEnd,Low);
                        copiedTotal = copiedLow;                                                                                                                                                                        // Will act as each Array(s) Size value
                        err++;
                } while((copiedTime == -1 || ArraySize(Time) == 0 ||
                                                (copiedTotal != copiedTime && copiedTotal != copiedVol && copiedTotal != copiedHigh)) && err < _NoOfAttempts);
                // Error copying data in _NoOfAttempts, exit calculationPOCs()
                if(err > _NoOfAttempts) 
                        return(false);

                //PrintFormat("%s err[%i] > [%i] timeSessionStart[%s] timeSessionEnd[%s] ArraySize Time[%i] Volume[%i] High[%i] Low[%i]",vMethod,err,_NoOfAttempts,TimeToString(timeSessionStart),TimeToString(timeSessionEnd),ArraySize(Time),ArraySize(Volume),ArraySize(High),ArraySize(Low));
                POCTimeStart = Time[0];

Help me what I have missed to check this error in do while loop.

Thanks in advance.

 

Pay attention to the possibility of copying synchronized time series into a set of arrays

Forum on trading, automated trading systems and testing trading strategies

New MetaTrader 5 build 3620: Web Terminal improvements, ONNX support and fast matrix multiplications in MQL5

MetaQuotes, 2023.03.03 11:14

MQL5: Added new CopySeries function for copying synchronized timeseries from MqlRates into separate arrays.

The CopySeries function allows obtaining only the necessary timeseries into different specified arrays during one call, while all of timeseries data will be synchronized. This means that all values in the resulting arrays at a certain index N will belong to the same bar on the specified Symbol/Timeframe pair. Therefore, there is no need for the programmer to additionally synchronize the received timeseries by the bar opening time.

Unlike CopyRates, which returns the full set of timeseries as an MqlRates array, the CopySeries function allows obtaining specific required timeseries into separate arrays. This can be done by specifying a combination of flags to select the type of timeseries. The order of the arrays passed to the function must match the order of the fields in the MqlRates structure:

struct MqlRates
  {
   datetime time;         // period beginning time
   double   open;         // open price
   double   high;         // high price for the period
   double   low;          // low price for the period
   double   close;        // close price
   long     tick_volume;  // tick volume
   int      spread;       // spread
   long     real_volume;  // exchange volume
  }

Thus, if you need to get the values of the 'time', 'close' and 'real_volume' timeseries for the last 100 bars of the current Symbol/Timeframe, you should use the following call:

datetime  time[];
double    close[];
long      volume[];
CopySeries(NULL,0,0,100,COPY_RATES_TIME|COPY_RATES_CLOSE|COPY_RATES_VOLUME_REAL,time,close,volume);

The order of the arrays "time, close, volume" must match the order of the fields in the MqlRates structure. The order of values in the rates_mask is ignored. The mask could be as follows:

COPY_RATES_VOLUME_REAL|COPY_RATES_TIME|COPY_RATES_CLOSE

Example

//--- input parameters
input datetime InpDateFrom=D'2022.01.01 00:00:00';
input datetime InpDateTo  =D'2023.01.01 00:00:00';
input uint     InpCount   =20;
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart(void)
  {
//--- arrays to get timeseries from the Rates structure
   double   open[];
   double   close[];
   float    closef[];
   datetime time1[], time2[];
//---request close prices to a double array
   ResetLastError();
   int res1=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount,
                       COPY_RATES_TIME|COPY_RATES_CLOSE, time1, close);
   PrintFormat("1. CopySeries  returns %d values. Error code=%d", res1, GetLastError());
   ArrayPrint(close);
   

//--- now also request open prices; use float array for close prices
   ResetLastError();
   int res2=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount,
                       COPY_RATES_TIME|COPY_RATES_CLOSE|COPY_RATES_OPEN, time2, open, closef);
   PrintFormat("2. CopySeries  returns %d values. Error code=%d", res2, GetLastError());
   ArrayPrint(closef);
//--- compare the received data
   if((res1==res2) && (time1[0]==time2[0]))
     {
      Print("  | Time             |    Open      | Close double | Close float |");
      for(int i=0; i<10; i++)
        {
         PrintFormat("%d | %s |   %.5f    |   %.5f    |   %.5f   |",
                     i, TimeToString(time1[i]), open[i], close[i], closef[i]);
        }
     }
/*  Result
        1. CopySeries  returns 0 values. Error code=0
        [ 0] 1.06722 1.06733 1.06653 1.06520 1.06573 1.06649 1.06694 1.06675 1.06684 1.06604
        [10] 1.06514 1.06557 1.06456 1.06481 1.06414 1.06394 1.06364 1.06386 1.06239 1.06247
        2. CopySeries  returns 0 values. Error code=0
        [ 0] 1.06722 1.06733 1.06653 1.06520 1.06573 1.06649 1.06694 1.06675 1.06684 1.06604
        [10] 1.06514 1.06557 1.06456 1.06481 1.06414 1.06394 1.06364 1.06386 1.06239 1.06247
          | Time             |    Open      | Close double | Close float |
        0 | 2023.03.01 17:00 |   1.06660    |   1.06722    |   1.06722   |
        1 | 2023.03.01 18:00 |   1.06722    |   1.06733    |   1.06733   |
        2 | 2023.03.01 19:00 |   1.06734    |   1.06653    |   1.06653   |
        3 | 2023.03.01 20:00 |   1.06654    |   1.06520    |   1.06520   |
        4 | 2023.03.01 21:00 |   1.06520    |   1.06573    |   1.06573   |
        5 | 2023.03.01 22:00 |   1.06572    |   1.06649    |   1.06649   |
        6 | 2023.03.01 23:00 |   1.06649    |   1.06694    |   1.06694   |
        7 | 2023.03.02 00:00 |   1.06683    |   1.06675    |   1.06675   |
        8 | 2023.03.02 01:00 |   1.06675    |   1.06684    |   1.06684   |
        9 | 2023.03.02 02:00 |   1.06687    |   1.06604    |   1.06604   |
*/
  }

 
Vladislav Boyko #:

Pay attention to the possibility of copying synchronized time series into a set of arrays


Thanks @Vladislav Boyko

I was not aware of this method :). Let me try to revise my code accordingly and revert back if any problem occurred.

Regards.

 
Vladislav Boyko #:

Pay attention to the possibility of copying synchronized time series into a set of arrays


Hi @Vladislav Boyko 

I have tried to change code as below 

                int err = 0;
                int barStart = MathMin(RatesTotal,iBarShift(mSymbol,PERIOD_M1,timeSessionStart));               // Returns -1 as failure
                int barCount = int(PeriodSeconds(mSessionTF) / 60);
                int barCopied = 0;
                do{
                        ResetLastError();
                        int barCopied = CopySeries(mSymbol,PERIOD_M1,barStart,barCount,
                                                   COPY_RATES_TIME|COPY_RATES_HIGH|COPY_RATES_LOW|COPY_RATES_VOLUME_TICK,
                                                   Time,High,Low,Volume);
                        err++;
                } while(barCopied == -1 && err < _NoOfAttempts);
                if(err > _NoOfAttempts)                                                                                                                                                                                                                                                                                                                                                         return(false);
//RatesTotal[60709] barStart[60708][2023.08.31 00:00] barStop[2023.09.01 00:00] barCount[1440] barCopied[-1] GetLastError[0] Time[0] High[0] Low[0] Volume[0]
but continued to get the same error.

Regards

 
Anil Varma #:

Hi @Vladislav Boyko 

I have tried to change code as below 

Regards

To be honest, I don't have a reliable solution for copying timeseries in MQL5. I just suggested replacing 4 CopyXXX calls with one, thereby obtaining synchronized arrays.

If the array out of range error occurs here

POCTimeStart = Time[0];

Then you can try to avoid this error something like this

if(ArraySize(Time) < 1)
  {
   // Here you can print the error with debugging information
   return(false);
  }
POCTimeStart = Time[0];

But this will be just a crutch that will help avoid errors when accessing the zero element of the array.

As I already said, I don't know how to reliably copy timeseries in MQL5

 
Vladislav Boyko #:
To be honest, I don't have a reliable solution for copying timeseries in MQL5. I just suggested replacing 4 CopyXXX calls with one, thereby obtaining synchronized arrays.

Dear @Vladislav Boyko

really appreciate your time and suggestion.

I understand you point now how it is possible to replace 4CopyXXX calls with one and obtaining synchronized arrays.

To copy data, I will look solutions to make sure required or synchronized bars have been copied.

I just wonder how it has by passed do..while loop, where the check was in place.

Regards.

 
Anil Varma #:
I just wonder how it has by passed do..while loop, where the check was in place.
if(err > _NoOfAttempts) 
   return(false);

The condition above was not met because "err" was equal to "_NoOfAttempts". That is, the maximum number of attempts was reached, but you did not return false.

 
void OnStart()
  {
   int _NoOfAttempts = 3;
   int err = 0;
   do{
           err++;
   } while(err < _NoOfAttempts);
   PrintFormat("The cycle is complete: err = %i, _NoOfAttempts = %i", err, _NoOfAttempts);
   if(err > _NoOfAttempts) 
      Print("return was executed");
   else Print("return was not executed");
  }
The cycle is complete: err = 3, _NoOfAttempts = 3
return was not executed
 
Vladislav Boyko #:

Thanks Vladislav for highlighting the loo pole in my code.

Will explore it in more details.

 

//---request close prices to a double array
   ResetLastError();
   int res1=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount,
                       COPY_RATES_TIME|COPY_RATES_CLOSE, time1, close);
   PrintFormat("1. CopySeries  returns %d values. Error code=%d", res1, GetLastError());
   ArrayPrint(close);
   

//--- now also request open prices; use float array for close prices
   ResetLastError();
   int res2=CopySeries(NULL, PERIOD_CURRENT, 0, InpCount,
                       COPY_RATES_TIME|COPY_RATES_CLOSE|COPY_RATES_OPEN, time2, open, closef);
   PrintFormat("2. CopySeries  returns %d values. Error code=%d", res2, GetLastError());
   ArrayPrint(closef);

@Vladislav Boyko

Greetings and hope you are doing well.

I have tried all possible ways to use CopySeries() function and following are my observation after failing to succeed in any one of them.

1] If you have timeStart and timeStop parameters and not idxStart and NoOfCount values, this function creates lot of difficulties to convert time to index values. iBarShift()  has its own issues for returning incorrect values for many reasons.

2] The problem aggravates, if your start time is on a different timeframe than timeframe required for copying data.

3] MQL should consider another variation of this function with timePosStart and timePosEnd

int  CopySeries(
   string           symbol_name,       // symbol name
   ENUM_TIMEFRAMES  timeframe,         // period
   int              start_pos,         // start position
   int              count,             // amount to copy
   ulong            rates_mask,        // combination of flags to specify the requested series
   void&            array1[],          // array to receive the data of the first copies timeseries
   void&            array2[]           // array to receive the data of the second copied timeseries
   ...
   );
 
Anil Varma #:

As I already said, I don't have a reliable solution for copying timeseries in mql5.

Here and here I pointed out a bug in your code from your first post that resulted in an array out of bounds. I'm afraid I can't help you with anything else.