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

 
Alain Verleyen #:
Why were you thinking it's not an option to “find out how much you need to copy and copy exactly this amount” ?

Because I don’t remember a single case where I knew the exact date, but did not know the number of bars. I don't know what might cause the situation where you know the exact date before copying the bars. Usually the date is unknown to me too😄

Perhaps this is due to the fact that I have little experience with MT5...

 
Vladislav Boyko #:
Perhaps this is due to the fact that I have little experience with MT5...

That's why I asked my question. I have not yet decided on the approach to use in MT5 for copying quotes. In MT4 I have direct access to the chart without having to copy anything or allocate memory.

I'm still wondering which approach would be best for MT5. When I don’t know in advance exactly how many bars I will need (to find some “last signal,” for example).

  • copy with each tick the last few thousand bars “with a margin”;
  • store snapshot;
  • try to process the entire chart once after launch, caching the processing result, and then work only with the 2 newest bars, updating the cached results
  • ...
 
Alain Verleyen #:
iBarShift() is not returning incorrect values. I have never seen it and I used it very intensively.

Hi @Alain Verleyen

Thanks for your reply.

What I meant to say was that iTime(Symbol,HigherTimeFrame,iBarShift(Symbol,LowerTimeFrame)) was returning 1970.01.00 00:00, which I think is the start date of data series and caused by iBarShift returning -1 value.

I even tried to use following function and avoid getting return value as -1, but failed to get desired results.

int CAccessTimeseries::getBarShift(ENUM_TIMEFRAMES timeframe,datetime time, bool exact=false) {

                string vMethod = "[" + mSymbol + "," + EnumToString(timeframe) + "] " + __FUNCTION__;

                int attempt  = 0;
                int barShift = 0;
                do{
                        ResetLastError();
                        barShift = iBarShift(mSymbol,timeframe,time);
                        attempt++;
                } while(barShift == -1 && attempt <= mNoOfAttempts);

} // End of method getBarShift()

The requirement is to find first PERIOD_M1 bar index (to be passed into CopySeries()) for say time = 2024.01.29 00:00, where M1 bar will never be at 00:00 Hrs:Minute as broker starts at 01:01.

Hence bool exact = true does not work and false return index prior to the 'time' specified.

I even tried following function to get first bar of lower time frame [https://www.mql5.com/en/articles/599#access_bar_time] but this time even this failed to work.

bool CAccessTimeseries::getFirstBarTime(ENUM_TIMEFRAMES timeframeFirstBar,datetime timeUpperTFBar,datetime &timeFirstBar) {

                datetime Time[];
                // determine the bar time on a lower time frame corresponding to the bar time on a higher time frame 
                if(CopyTime(mSymbol,timeframeFirstBar,timeUpperTFBar,1,Time) == -1) {
                        return(false);
                }

                if(Time[0] < timeUpperTFBar) {
                        // we got the time of the preceding bar
                        datetime Time2[];
                        // determine the time of the last bar on a lower time frame
                        if(CopyTime(mSymbol,timeframeFirstBar,0,1,Time2) == -1) {
                                return(false);
                        }

                        if(Time[0] < Time2[0]) {
                                // there is a bar following the bar of a lower time frame that precedes the occurrence of the bar on a higher time frame
                                int start = Bars(mSymbol,timeframeFirstBar,Time[0],Time2[0]) - 2;
        
                                // the Bars() function returns the number of bars from the bar with time Time[0] to the bar with time Time2[0];
                                // since we need to determine the index of the bar following the bar with time Time2[2], subtract 2
                                if(CopyTime(mSymbol,timeframeFirstBar,start,1,Time) == -1) {
                                  return(false);
                                }
                        } else {
                                // there is no bar of a lower time frame contained in the bar on a higher time frame
                                timeFirstBar = 0;
                                return(true);
                        }
                }
                // assign the obtained value to the variable 
                timeFirstBar = Time[0];
                return(true);

} // End of method getFirstBarTime()
MQL5 Programming Basics: Time
MQL5 Programming Basics: Time
  • www.mql5.com
The article focuses on standard MQL5 functions for working with time, as well as programming techniques and practically useful functions for working with time that are required when creating Expert Advisors and indicators. Particular attention is paid to the general theory of time measurement. This article should be of interest primarily to novice MQL5 programmers.
 
Alain Verleyen #:
I am mainly working on multi-symbols and multi-timeframes indicators/EA. So it's not only getting data for 1 symbol on 1 given timeframe, but up to 35 symbols and 2 or more timeframes. And it needs to work in all situations, when you attach an indicator on a chart, but also when you restart the platform, when it's the week-end, when the computer goes in sleep mode, etc... There is also the need to synchronize data among symbols, and sometimes also among timeframes. It's a complex task. There is never any option which can't be considered when you have a problem to solve.

@Alain Verleyen This is what my ultimate goal is :)

However I am still struggling with single symbol.

 
Anil Varma #:

@Alain Verleyen This is what my ultimate goal is :)

However I am still struggling with single symbol.

You need to understand and deal, with the asynchronous nature of the data functions.

Using loop or sleep is a bad approach. When a data function returns -1 it (usually) means the data are not ready. The best approach is then to use events, either waiting the next tick, or forcing some events with a timer or custom event.

 
Vladislav Boyko #:

I was just measuring the time for ArrayCopyRates yesterday. The advisor spends ~15 microseconds with each tick to keep 3 charts up to date (very old and bad computer).

15 microseconds is ArrayCopyRates + RefreshRates + checks. After these 15 microseconds, you have 3 complete, up-to-date charts at your disposal.

But ArrayCopyRates is closely related to the MT4 architecture. Perhaps due to the different architecture, OnTick in MT5 has much lower latency. I find ArrayCopyRates to be very fast for MT4.

MT5 does not have ArrayCopyRates due to the way the terminal works differently (because of this, MT5 is faster and has more features). Perhaps you meant CopyRates and not ArrayCopyRates.

I mean ArrayCopyRates. It's always the slowest method (which is logical as it gets all data of a given symbol/period).


This is retrieving 50000 bars on 28 symbols, 1 timeframe, on MT4.

 
Alain Verleyen #:
The best approach is then to use events, either waiting the next tick, or forcing some events with a timer or custom event.

Thanks @Alain Verleyen

any pointer to article / help on this will be highly appreciated.

Dose adding below function (got it from one of the article in the Forum), in the code will help to make sure data is synchronized?

                // Check if history data is synchronized in maximum 10 attempts
                int attempt = 0;
                datetime serverFirstDate = (datetime)SeriesInfoInteger(mSymbol,timeframe,SERIES_SERVER_FIRSTDATE);
                // checkLoadHisory() returns 0,1 or 2, if bars are synchronized with history, hence used >= 0
                while(!(checkLoadHistory(timeframe,serverFirstDate) >= 0) && attempt <= 10) {
                        Sleep(200);                                                                                                                                                                                                                             // Wait time in milliseconds
                        attempt++;
                }

I have tried to modify OnTick() in Base Class method as below.

//+-----------------------------------------------------------------------------------------------------------------------------+
//| METHOD:       OnTick()
//| APPLICATION:  
//+-----------------------------------------------------------------------------------------------------------------------------+
void CSessionVPBase::OnTick(void) {

                string vMethod = "[" + mSymbol + "," + TimeToString(TimeCurrent()) + "] " + __FUNCTION__;
        //+---------------------------------------------------------------------------------------------------------------------------+
        //| Check for the symbol synchronisation before the beginning of calculations
        //+---------------------------------------------------------------------------------------------------------------------------+
                int attempt = 0;
                while(!(bool)SeriesInfoInteger(mSymbol,PERIOD_M1,SERIES_SYNCHRONIZED) &&
                      !(bool)SeriesInfoInteger(mSymbol,mSessionTF,SERIES_SYNCHRONIZED) && attempt <= _NoOfAttempts) {
                  Sleep(500);
                  attempt++;
                }
                // Data not yet ready, Exit and wait for next tick
                if(attempt > _NoOfAttempts) {
                        PrintFormat("%s: Data not Synchronized yet, try on next tick",vMethod,);
                        return;
                }

                int profileCounts;
        //+---------------------------------------------------------------------------------------------------------------------------+
        //| Check for presence of the new Volume Profile Session
        //+---------------------------------------------------------------------------------------------------------------------------+
                attempt = 0;
                if(mRatesTotal != Bars(mSymbol,mSessionTF)) {
                        ... commented out while..loop
			//while(!Init() && attempt <= _NoOfAttempts) {                                                                                    // loop until Init() returns [true]
                        //attempt++;
                        }
			... calculation code here
                }
        //+---------------------------------------------------------------------------------------------------------------------------+
        //| Refresh data, if it is current[0] Volume Profile Session
        //+---------------------------------------------------------------------------------------------------------------------------+
                else {
			... calculation code here
                }

} // End of method OnTick()
 

@Alain Verleyen #: I mean ArrayCopyRates. It's always the slowest method (which is logical as it gets all data of a given symbol/period). This is retrieving 50000 bars on 28 symbols, 1 timeframe, on MT4.

Due to a website malfunction, your embedded image was not properly saved. Please repost the image. Thank you!

 
Fernando Carreiro #:

Due to a website malfunction, your embedded image was not properly saved. Please repost the image. Thank you!

Done. Thanks.
 
Anil Varma #:

Thanks @Alain Verleyen

any pointer to article / help on this will be highly appreciated.

Dose adding below function (got it from one of the article in the Forum), in the code will help to make sure data is synchronized?

I have tried to modify OnTick() in Base Class method as below.

I have not seen any useful article on this. Only some discussions on this forum, please search.

Reason: