High-performance iTimeSeries for time-sensitive applications - MetaTrader 5 Library - MT4/MT5 Resources


One of the main problems with MQL5 is the removal of built-in time series functions. While this gives the programmer more limited development freedom, it is also slowed down by the need to create and destroy new memory locations every time some time series data needs to be accessed.
... if ( copytime (symbol,timerange,time, 1 ,checkcandle)== 1 ) { ...
Let's take a look at the popular iBarShift algorithm. In order to return the index of the bar by datetime - we first have to call ::CopyTime(...), which creates a dynamic array, resizes it, copies the data and then destroys it in memory. This isn't a problem for a few occasional calls, but since time series functions are often called multiple times over many different time frames, this memory overhead can increase, causing significant slowdowns. Think about all the potential bloat overhead and waste of resources required to allocate new memory every time your program calls any time series data using these types of methods.
To speed things up, the library implements the CObject and CArrayObj classes of the standard library to copy the rates array once and then revisit it from all time series calls for that specific symbol and period. This can be a double-edged sword, as the initialization phase takes longer than a typical implementation, but all subsequent calls can access the data in about 1/100th the time. In the example of iBarShift(), this new algorithm works faster by creating an int[] array that stores the index integer of the bar in the array and then accessing it using the time (converted to type int) as the array address. In other words, you pass the time as a direct address to access the data.
This brings us to some caveats:
Most of the time is spent in the initialization phase . If you don't plan to access the time series data more than a few thousand (total) times per period you may want to consider another approach.
Objects of the CiTimeSeries class are set up to automatically refresh the stored data when a new bar is formed. Setting this to "false" will put the object into high-performance mode allowing lightning-fast calls from the mission-critical "hot path" but requiring manual refreshes during subsequent maintenance cycles.
#include//--- Global declaration of iTimeSeries object CiTime series iBar; during integer initialization () { //--- Initialization phase iBar.Init( invalid , PERIOD_CURRENT, wrong //Boolean value automatically refreshed ); //--- return ( initialization successful ); } //+------------------------------------------------------------------+ //|Expert check function | //+------------------------------------------------------------------+ Blank check () { //--- if (hot path operation) { //Example index = iBar.Shift(time); } Else if (maintenance path operation) { iBar.Refresh(); } }
Furthermore, you can call global functions directly (just like in MQL4) without instantiating a CiTimeSeries object, but the first access time will be slow, since it must first initialize the global object behind the scenes. Using the library this way may be slower if you only call any time series function a few times, but there are clear performance benefits when your algorithm needs to be called (>) thousands of times series data iterations from the same symbol+period set.
The developers of the (currently) most popular iBarShift algorithm conducted a competitive benchmark for "iBarShift" which you can find here https://www.mql5.com/en/code/1864 .

Since this is the most accurate and fastest method (at the time of writing this article), I decided to use it as a benchmark.

Computation time for 100,000 direct (global) function calls is 50 times faster than the fastest method currently available, while calling public methods after initialization in "Performance Mode" is over 100 times faster .
Available public methods and global functions:
Note: Global functions are the same as MetaTrader 4, such as iBarShift, iTime, etc.
//--- Initialize a symbol and period; set automatic refresh of performance mode to false boolean initialization ( thin string symbol = invalid , ENUM_TIMEFRAMES PERIOD = PERIOD_CURRENT , const boolean autorefresh = true ); //--- initialize a symbol and all periods in the ENUM_TIMEFRAMES array; set autorefresh for performance mode to false boolean initialize( string symbol, ENUM_TIMEFRAMES &periods[], const boolean autorefresh= true );
//--- initialize all periods boolean initialize all periods ( string symbol = invalid , const boolean autorefresh= true );
//--- Set autorefresh to false to manually manage data refresh blanks autorefresh ( const boolean reference ) { m_autoRefresh= reference ; } Boolean value autorefresh() constant { return m_autoRefresh; }
//--- Manual refresh call; refresh the data Boolean value of all initialization cycles refresh();
Attachment download
📎 itimeseries_nicholishen_v2.mqh (42.05 KB)
📎 itimeseries_example_1.mq5 (4.5 KB)
Source: MQL5 #18305
💡 Featured Recommendations
✍️ Latest by the author
- •
- •
- •
- •
- •
- •
📌 Popular topics
- •
- •
- •
- •
- •
- •
- •
- •
🔗 You May Be Interested In
- •
- •
- •
- •
- •
- •