Discussing the article: "Advanced Memory Management and Optimization Techniques in MQL5"

 

Check out the new article: Advanced Memory Management and Optimization Techniques in MQL5.

Discover practical techniques to optimize memory usage in MQL5 trading systems. Learn to build efficient, stable, and fast-performing Expert Advisors and indicators. We’ll explore how memory really works in MQL5, the common traps that slow your systems down or cause them to fail, and — most importantly — how to fix them.

MQL5 is undeniably powerful, but with that power comes responsibility — especially when it comes to memory. Many developers focus solely on strategy logic, entry points, and risk management, while memory handling quietly becomes a ticking time bomb in the background. As your code scales — processing more symbols, higher frequencies, and heavier datasets — ignoring memory can lead to performance bottlenecks, instability, and missed opportunities.

In this article, we’re going under the hood. We’ll explore how memory really works in MQL5, the common traps that slow your systems down or cause them to fail, and — most importantly — how to fix them. You’ll learn practical optimization techniques that make your trading programs faster, leaner, and more reliable.

Here’s where efficient memory usage really matters:

  • High-Frequency Trading: Every millisecond is a potential edge — or a potential loss.

  • Multi-Timeframe Analysis: Combining charts? Expect memory pressure to multiply.

  • Heavy Indicator Logic: Complex math and big datasets can grind everything to a halt if unmanaged.

  • Backtesting Large Histories: Without smart optimization, backtests can feel like watching paint dry.

If you’re ready to get serious about performance, let’s dive in — and make your MQL5 systems as efficient as they are intelligent.

Author: Sahil Bagdi

 

The article looks very debatable (just a couple of points).

What is the class you have mentioned here?

// Class member variable - created once
double prices[];

void OnTick()
{
   // Reuse the existing array
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Process the data...
}

From the presence of OnTick handler and how the array is accessed it's implied that you added the prices array into global scope, which is a bad idea (because of the namespace pollution, if the array is only needed in the handler's scope). Probably it would be more appropriate to keep inital code from the same example, but made the array static, this way everyone clearly see the difference:

// Efficient approach (allocates the array once, can adjust its size if necessary)
void OnTick()
{
   // This does NOT create (nor allocate) array on every tick
   static double prices[];
   ArrayResize(prices, 1000);
   
   // Fill the array with price data
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Process the data...
}

Also, if you replace Array of Structures (AoS) with Structure of Arrays (SoA) for OHLCV - the access to the prices of the same bar needs more references (switching between arrays instead of incrementing offset inside a single structure) and slows down the process, but such operations are very common.

For this example with OHLCV, to make it more appropriate for memory and time efficiency, it would be probably more interesting to pack all values into a single 2D or even 1D array:

double TOHLCV[][6];

This is possible because all values of types (double, datetime, long) have the same size 8 byte and can be casted to each other directly.

 
Stanislav Korotky #:
For this example with OHLCV, to make it more appropriate for memory and time efficiency, it would be probably more interesting to pack all values into a single 2D or even 1D array:

A 2D array instead of an array of structures may slightly save processor time, but it will greatly increase the developer's time spent on developing and maintaining code. In my personal opinion. I agree with the rest of your statements.

 

https://www.mql5.com/en/articles/17693#sec2

Let's look at a problematic example:

// Inefficient approach - creates new arrays on every tick
void OnTick()
{
   // This creates a new array on every tick
   double prices[];
   ArrayResize(prices, 1000);
   
   // Fill the array with price data
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Process the data...
   
   // Array will be garbage collected eventually, but this
   // creates unnecessary memory churn
}

A more efficient approach would be:

// Class member variable - created once
double prices[];

void OnTick()
{
   // Reuse the existing array
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Process the data...
}

Stanislav Korotky #:

The article looks very debatable (just a couple of points).

What is the class you have mentioned here?

From the presence of OnTick handler and how the array is accessed it's implied that you added the prices array into global scope, which is a bad idea (because of the namespace pollution, if the array is only needed in the handler's scope). Probably it would be more appropriate to keep inital code from the same example, but made the array static, this way everyone clearly see the difference:

As far as I understand, that example (I quoted it above) is, roughly speaking, pseudocode. That is, the author does not pay attention to the following (in order to concentrate on what exactly he is talking about, I guess):

  • Judging by the loop condition, the size of the array is known at compile time, but nevertheless, the array is dynamic.
  • Even though the array is dynamic, ArrayResize was not called in the code demonstrating the efficient approach.
  • In terms of efficiency, I suspect it would be better to replace the entire following loop with a single CopySeries call:

   // Reuse the existing array
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
 
Vladislav Boyko #:
In terms of efficiency, I suspect it would be better to replace the entire following loop with a single CopySeries call:

Correct me if I'm wrong, but as far as I remember, every iClose call contains a CopySeries call under the hood.