Discusión sobre el artículo "Técnicas avanzadas de gestión y optimización de la memoria en MQL5"

 

Artículo publicado Técnicas avanzadas de gestión y optimización de la memoria en MQL5:

Descubra técnicas prácticas para optimizar el uso de la memoria en los sistemas de trading MQL5. Aprenda a crear asesores expertos e indicadores eficientes, estables y de rápido rendimiento. Exploraremos cómo funciona realmente la memoria en MQL5, las trampas comunes que ralentizan sus sistemas o provocan fallos y, lo más importante, cómo solucionarlos.

MQL5 es innegablemente potente, pero ese poder conlleva una gran responsabilidad, especialmente en lo que respecta a la memoria. Muchos desarrolladores se centran únicamente en la lógica estratégica, los puntos de entrada y la gestión de riesgos, mientras que la gestión de la memoria se convierte silenciosamente en una bomba de relojería en segundo plano. A medida que su código se amplía (procesando más símbolos, frecuencias más altas y conjuntos de datos más pesados), ignorar la memoria puede provocar cuellos de botella en el rendimiento, inestabilidad y oportunidades perdidas.

En este artículo vamos a profundizar en el tema. Exploraremos cómo funciona realmente la memoria en MQL5, las trampas comunes que ralentizan sus sistemas o provocan fallos y, lo más importante, cómo solucionarlos. Aprenderás técnicas prácticas de optimización que harán que tus programas de trading sean más rápidos, ágiles y fiables.

Aquí es donde realmente importa el uso eficiente de la memoria:

  • Trading de alta frecuencia: Cada milisegundo es una ventaja potencial... o una pérdida potencial.

  • Análisis en múltiples marcos temporales: ¿Combinar gráficos? Es de esperar que la presión sobre la memoria se multiplique.

  • Lógica de indicadores pesados: Las matemáticas complejas y los grandes conjuntos de datos pueden paralizarlo todo si no se gestionan adecuadamente.

  • Pruebas retrospectivas de historiales extensos: Sin una optimización adecuada, las pruebas retrospectivas pueden parecer un proceso tedioso.

Si está listo para tomarse en serio el rendimiento, vamos a ponernos manos a la obra y hacer que sus sistemas MQL5 sean tan eficientes como inteligentes.



Autor: Sahil Bagdi

 

El artículo parece muy discutible (sólo un par de puntos).

¿Cuál es la clase que has mencionado aquí?

// Variable miembro de clase - created once
double prices[];

void OnTick()
{
   // Reutilizar la matriz existente
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Procesa los datos...
}

De la presencia del manejador OnTick y de cómo se accede al array se deduce que has añadido el array de precios al ámbito global, lo cual es una mala idea (debido a la contaminación del espacio de nombres, si el array sólo se necesita en el ámbito del manejador). Probablemente sería más apropiado mantener el código inicial del mismo ejemplo, pero haciendo el array estático, de esta forma todo el mundo vería claramente la diferencia:

// Enfoque eficiente (asigna el array una vez, puede ajustar su tamaño si es necesario)
void OnTick()
{
   // Esto NO create (nor allocate) array on every tick
   static double prices[];
   ArrayResize(prices, 1000);
   
   // Rellenar el array con datos de precios
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Procesa los datos...
}

Además, si se sustituye Array of Structures (AoS) por Structure of Arrays (SoA) para OHLCV - el acceso a los precios de la misma barra necesita más referencias (cambiar entre arrays en lugar de incrementar el offset dentro de una única estructura) y ralentiza el proceso, pero este tipo de operaciones son muy comunes.

Para este ejemplo con OHLCV, para hacerlo más apropiado para la eficiencia de memoria y tiempo, sería probablemente más interesante empaquetar todos los valores en un único array 2D o incluso 1D:

double TOHLCV[][6];

Esto es posible porque todos los valores de los tipos (double, datetime, long) tienen el mismo tamaño 8 byte y pueden ser casteados entre sí directamente.

 
Stanislav Korotky #:
Para este ejemplo con OHLCV, para hacerlo más apropiado para la eficiencia de memoria y tiempo, sería probablemente más interesante empaquetar todos los valores en un único array 2D o incluso 1D:

Un array 2D en lugar de un array de estructuras puede ahorrar ligeramente tiempo de procesador, pero aumentará mucho el tiempo que el desarrollador dedica a desarrollar y mantener el código. En mi opinión personal, estoy de acuerdo con el resto de tus afirmaciones.

 

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

Veamos un ejemplo problemático:

// Enfoque ineficiente - crea nuevas matrices en cada tick
void OnTick()
{
   // Esto crea un nuevo array en cada tick
   double prices[];
   ArrayResize(prices, 1000);
   
   // Rellenar el array con datos de precios
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Procesa los datos...
   
   // El array será recolectado eventualmente, pero este
   // crea un flujo de memoria innecesario
}

Un enfoque más eficiente sería:

// Variable miembro de clase - creada una vez
double prices[];

void OnTick()
{
   // Reutilizar la matriz existente
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
   
   // Procesa los datos...
}

Stanislav Korotky #:

El artículo parece muy discutible (sólo un par de puntos).

¿Cuál es la clase que se menciona aquí?

Por la presencia del manejador OnTick y la forma en que se accede al array se deduce que has añadido el array de precios al ámbito global, lo cual es una mala idea (debido a la contaminación del espacio de nombres, si el array sólo se necesita en el ámbito del manejador). Probablemente sería más apropiado mantener el código inicial del mismo ejemplo, pero haciendo el array estático, de esta forma todo el mundo vería claramente la diferencia:

Por lo que tengo entendido, ese ejemplo (lo he citado más arriba) es, a grandes rasgos, pseudocódigo. Es decir, el autor no presta atención a lo siguiente (para concentrarse en lo que está hablando exactamente, supongo):

  • A juzgar por la condición del bucle, el tamaño del array se conoce en tiempo de compilación, pero sin embargo, el array es dinámico.
  • Aunque el array es dinámico, ArrayResize no fue llamado en el código que demuestra el enfoque eficiente.
  • En términos de eficiencia, sospecho que sería mejor sustituir todo el bucle siguiente por una única llamada a CopySeries:

   // Reutilizar la matriz existente
   for(int i = 0; i < 1000; i++)
   {
      prices[i] = iClose(_Symbol, PERIOD_M1, i);
   }
 
Vladislav Boyko #:
En términos de eficiencia, sospecho que sería mejor sustituir todo el bucle siguiente por una única llamada CopySeries:

Corrígeme si me equivoco, pero por lo que recuerdo, cada llamada iClose contiene una llamada CopySeries bajo el capó.

 

Este artículo ofrece un contenido perspicaz y sugerente para el debate.

La presentación técnica es clara y está bien explicada, lo que facilita el seguimiento y la participación del lector.

Muchas gracias.

 

Estos artículos necesitan pruebas comparativas motivadoras que demuestren realmente la eficacia de los enfoques propuestos.

La traducción está torcida, no es fácil de entender sin analizar el código.