English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Tester la performance du Calcul des Moyennes Mobiles dans MQL5

Tester la performance du Calcul des Moyennes Mobiles dans MQL5

MetaTrader 5Exemples | 17 novembre 2021, 15:29
285 0
Sergey Pavlov
Sergey Pavlov


Introduction

L'utilisation de Moyennes Mobiles est une pratique courante dans l'analyse des séries chronologiques de marché, dans les indicateurs et la programmation des Expert Advisors. C'est la méthode de lissage des données de prix la plus populaire. Dans la nouvelle version du langage MQL, une douzaine d'algorithmes de Moyenne Mobile est disponible.

C'est la différence entre eux ? Vraiment, la vitesse de calcul dépend-elle de certains algorithmes de Moyennes Mobiles ? Quel algorithme est le plus rapide ?

La vitesse de calcul des Moyennes Mobiles a-t-elle augmenté dans MetaTrader 5 par rapport à MetaTrader 4 ? Il y a beaucoup de telles questions qui surgissent. Alors, considérons la plupart d'entre elles.

Bien sûr, la vitesse d'une nouvelle plateforme est impressionnante, mais il vaut mieux la vérifier expérimentalement.


1. Conditions de test

La vitesse de calcul dépend de nombreux facteurs. Par conséquent, les données obtenues à la suite de cette recherche, dans d'autres conditions d'essai, seraient différentes. En d'autres termes, les valeurs absolues de performance seront différentes, mais les valeurs relatives devraient être similaires (pour une certaine plate-forme).

Du fait que la fonction iMA dans MQL5 ne renvoie pas elle-même les résultats du calcul (elle renvoie la poignée d'un indicateur), nous allons tester la vitesse de deux fonctions : iMA et CopyBuffer.

Conditions de test:
  • Processeur Core i7 965
  • Symbole "EURUSD"
  • Taille des données de prix : 10000 éléments
  • Terminal client : autonome, le nombre maximum de barres dans le graphique est fixé à 10000
  • Modèles de Moyenne Mobile : MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA
  • La précision de la vitesse de calcul est limitée à deux chiffres significatifs
  • Le nombre d'appels possibles des fonctions Moyennes Mobiles : 7


2. Comment nous avons testé

Pour mesurer le temps de calcul des Moyennes Mobiles, nous avons la fonction GetTickCount(), qui opère en millisecondes. Cette précision n'est pas suffisante, il faut donc organiser des cycles pour améliorer la qualité des mesures.

Cependant, si nous répétons la boucle plusieurs fois avec le même calcul et les mêmes données d'entrée, les résultats seront faussés. La raison de ce fait est la suivante : la fonction iMA crée une copie de l'indicateur technique correspondant dans le cache global du terminal client. Si la copie d'un indicateur (avec les mêmes paramètres) est déjà présente dans le cache global, la nouvelle copie n'est pas créée, le compteur de référence de la copie de l'indicateur est augmenté.

En d'autres termes, l'ensemble de l'indicateur de tampon est calculé une seule fois au premier appel, et à tous les appels suivants, il ne prend que les valeurs prêtes, il ne recalcule que les nouvelles données.

Par conséquent, la boucle doit être organisée de la manière, lorsque les paramètres d'entrée de l'indicateur sont uniques durant le cycle. Nous avons sélectionné trois de ces paramètres : période de moyennage ; délai et prix appliqué.

Paramètre
 Fourchette des valeurs
 Période de moyenne
 de 1 à 100
 Délai
 М1, М5, М15, М30
 Prix appliqué
 PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED

Tableau1. Les fourchettes de paramètres d'entrée

Nous allons calculer les valeurs de moyenne mobile pour le tableau avec 10000 éléments en utilisant les sept méthodes d'appel différentes (voir les détails dans la section 4).


3. Les conclusions de l'étude

Nous avons combiné tous les résultats dans le tableau 1, la performance de calcul est estimée en utilisant le temps de calcul (voir tableau 1) en secondes. Le programme calcule 100х4х7=2800 types de Moyennes Mobiles, et nous déterminons le temps de calcul pour le tableau des prix avec 10 000 éléments. Le temps de calcul du seul passage (cycle) est environ égal au temps total, divisé par 2800. Par exemple, pour le cas 1 et le mode SMA, il est égal à ~ 0,0028/2800.

Mode
MODE_SMA MODE_EMA MODE_SMMA MODE_LWMA Plateforme
0 (voir paragraphe 4.1)
0,0041 0,0040 0,0043 0,0041  MetaTrader 4
1 (voir paragraphe 4.2) 0,0028 0,00023 0,00027 0,0045  MetaTrader 5
2 (voir paragraphe 4.3) 0,0029 0,0029 0,0029 0,0029  MetaTrader 5
3 (voir paragraphe 4.4) 0,0998 0,0997 0,0998 0,0998  MetaTrader 5
4 (voir paragraphe 4.5) 0,0996 0,0996 0,0996 0,0996  MetaTrader 5
5 (voir paragraphe 4.6) 0,0030 0,0029 0,0029 0,0029  MetaTrader 5
6 (voir paragraphe 4.7) 0,000140 0,000121 0,000117 0,0035  MetaTrader 5

Tableau2. Les résultats

La signification des cas de test sera examinée plus en détail (paragraphes 4.1-4.7). Estimons l'ensemble de la performance de calcul de la Moyenne Mobile. 

Pour plus de commodité, les résultats sont présentés sous forme de graphiques (voir figures 1-5). Le type d'appel de la Moyenne Mobile est présenté sur les axes X (voir tableau 2), les valeurs sur les axes Y sont présentées en échelle logarithmique multipliée par -1, donc les valeurs les plus élevées signifient des performances plus rapides. Chacun des modèles de calcul (SMA, EMA, SMMA, LWMA) correspond à une colonne du graphique.

Figure.1 Résultats du test de performance pour différents algorithmes de Moyenne Mobile

Figure 1. Les résultats des tests de performance pour différents algorithmes de Moyenne Mobile

On peut voir une différence considérable de vitesse de calcul pour les différents cas de calcul des Moyennes Mobiles. Qu'est-ce que ça veut dire? Les différents algorithmes de calcul des Moyennes Mobiles, fournis par les développeurs de MQL5, ont des performances de calcul différentes : il existe un algorithme rapide (cas 6) et des méthodes plus lentes (cas 3 et 4). Il est donc nécessaire de choisir les bons algorithmes lors de l'écriture de programmes en MQL5, qui utilise les Moyennes Mobiles.

Le temps de calcul de chaque modèle de Moyennes Mobiles (0-6) est présenté en détail sur les figures suivantes, voir tableau 2.

Figure 2. la performance de calcul MA du mode MODE_SMA

Figure 2. La performance de calcul MA du mode MODE_SMA

Figure 3. La performance de calcul MA du mode MODE_EMA

Figure 3. la performance de calcul MA du mode MODE_EMA

Figure 4. la performance de calcul MA du mode MODE_SMMA

Figure 4. la performance de calcul MA du mode MODE_SMMA

Figure 5. la performance de calcul MA du mode MODE_LWMA

Figure 5. La performance de calcul MA du mode MODE_LWMA

Il est intéressant de comparer la performance de calcul de deux plateformes : MetaTrader 4 et MetaTrader 5. Les résultats sont présentés dans le tableau 2, cas №0 (MQL4) et cas №2 (MQL5).

Pour plus de commodité, combinons les résultats des calculs de l'indicateur standard iMA dans un graphique et un tableau séparés (voir fig. 6). Le temps de calcul du test est présenté en axes Y.

Figure 6. Tableau comparatif de performance de calcul de MetaTrader 4 et de MetaTrader 5

Figure 6. Tableau comparatif de performance de calcul de MetaTrader 4 et MetaTrader 5

Conclusion :

  1. La nouvelle plateforme MetaTrader 5 est 40% plus rapide que la précédente MetaTrader 4.
  2. La performance la plus rapide a été obtenue pour les modèles SMA, EMA et SMMA (cas №6), pour LWMA (cas №2 et №5).
  3. Pour les cas de test, lorsque l'indicateur standard iMA est utilisé, la performance de calcul des différents modèles sont quasiment identiques. Ce n'est pas vrai pour les fonctions de la bibliothèque MovingAverages.mqh. Pour différents modèles, la performance diffèrent de presque un ordre (0,00023 ~ 0,0045).
  4. Le résultat présenté correspond au "démarrage à froid", il n'y a pas de données précalculées dans le cache global du terminal client.


4. Études de cas

Les développeurs MQL5 recommandent la méthode suivante pour obtenir les valeurs des indicateurs techniques standard :

//---- indicator buffers
double      MA[];                // array for iMA indicator values
//---- handles for indicators
int         MA_handle;           // handle of the iMA indicator
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   //--- creating handle of the iMA indicator
   MA_handle=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE);
   //--- print message if there was an error
   if(MA_handle<0)
      {
      Print("The iMA object is not created: MA_handle= ",INVALID_HANDLE);
      Print("Runtime error = ",GetLastError());
      //--- forced termination of program
      return(-1);
      }
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
   //--- filling the MA[] array with current values of the iMA indicator
   //--- we will copy 100 elements, or return if there was an error
   if(CopyBuffer(MA_handle,0,0,100,MA)<=0) return;
   //--- set ordering of MA[] as timeseries
   ArraySetAsSeries(MA,true);  
   //--- here you can do anything with these data
  }

Cette méthode est décrite en détail dans l'article "MQL5 for Newbies : Guide d'utilisation des indicateurs techniques dans Expert Advisors".

Pour tester la performance de calcul des Moyennes Mobiles, il est préférable d'utiliser le script, car il est capable d'effectuer tous les calculs sans attendre les événements (par exemple, nouvel événement tick, etc.).

Il n'est pas nécessaire de créer un programme universel séparé pour tous les cas de test, nous allons donc créer un script séparé pour chaque cas de calcul MA.

Examinons donc en détail chacun des cas de calculs de Moyenne Mobile.


4.1. Cas №0

Dans ce cas, nous avons mesuré la performance de calcul de l'indicateur technique iMA de MQL4. Les calculs sont effectués dans MetaTrader4 et menées sur toutes les données.

Modèle Résultat Meilleur résultat
MODE_SMA 0,0041 0,000140 (cas 6)
MODE_EMA 0,0040 0,000121 (cas 6)
MODE_SMMA 0,0043 0,000117 (cas 6):
MODE_LWMA 0,0041 0,0029 (cas 2, 5)


Le code de ce cas est le suivant (MQL4) :

int         M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
int         P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      buf[];
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int start()
  {
   if(ArrayResize(buf,count)<0) return(-1);
   Print("START ");
   startGTC=GetTickCount();
//----
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
           Test0();
           }
        }
     }
//----
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   Print("Total time [msec] ",time);
   time=time/1000/m/p/periodMA;
   Print("Performance [sec] ",DoubleToStr(time, 10));
   return(0);
  }
//+------------------------------------------------------------------+
void Test0()
  {
//--- Model: MODE_SMA; MODE_EMA; MODE_SMMA; MODE_LWMA
   for(int i=0;i<count;i++)
     {
      buf[i]=iMA(NULL,M[m],periodMA,0,MODE_SMA,P[p],i);
     }
  }

Note: Ce code ne fonctionnera pas dans MetaTrader 5, car il est écrit en MQL4. Il doit être exécuté sur le terminal client MetaTrader 4.


4.2. Cas №1

Dans ce cas, nous avons effectué le calcul de 4 modèles : №1(SMA), №2(EMA), №3(SMMA) et №4(LWMA) en utilisant les fonctions de la bibliothèque MovingAverages.mqh.

Le calcul est effectué sur l'ensemble du tableau de données.

Modèle
 Résultat Meilleur résultat
MODE_SMA
0,0028
0,000140 (cas 6)
MODE_EMA
0,00023
0,000121 (cas 6)
MODE_SMMA
0,00027 0,000117 (cas 6):
MODE_LWMA
0,0045 0,0029 (cas 2 et 5)
#include <MovingAverages.mqh>
ENUM_TIMEFRAMES      M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE   P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      buf[],close[];
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   if(ArrayResize(buf,count)<0) return(-1);
   ArraySetAsSeries(buf,false);
   ArraySetAsSeries(close,false);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         CopyClose(_Symbol,M[m],0,count,close);
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test1(); // the test is here
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test1()
  {
   for(int i=0;i<count;i++)
     {
      buf[i]=SimpleMA(i,periodMA,close);
     }
  }
//+------------------------------------------------------------------+
void Test2()
  {
   buf[0]=close[0];
   for(int i=1;i<count;i++)
     {
      buf[i]=ExponentialMA(i,periodMA,buf[i-1],close);
     }
  }
//+------------------------------------------------------------------+
void Test3()
  {
   buf[0]=close[0];
   for(int i=1;i<count;i++)
     {
      buf[i]=SmoothedMA(i,periodMA,buf[i-1],close);
     }
  }
//+------------------------------------------------------------------+
void Test4()
  {
   for(int i=0;i<count;i++)
     {
      buf[i]=LinearWeightedMA(i,periodMA,close);
     }
  }

Note: Nous avons prévu d'utiliser les différents types de données dans le tableau, mais pour la simplicité, nous avons utilisé un seul tableau avec clôture des données de prix (cela n'affecte pas la performance des calculs).


4.3. Cas №2

Dans ce cas, nous avons utilisé l'indicateur technique standard iMA et le test №5.

Le calcul est effectué sur l'ensemble du tableau de données.

Modèle Résultat Meilleur résultat
MODE_SMA 0,0029 0,000140 (cas 6)
MODE_EMA 0,0029 0,000121 (cas 6)
MODE_SMMA 0,0029 0,000117 (cas 6):
MODE_LWMA 0,0029 0,0029 (cas 2 et 5)
ENUM_TIMEFRAMES      M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE   P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
double      MA[];                // array for the iMA indicator
int         MA_handle;           // handle of the iMA indicator
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test5();
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test5()
  {
//--- Model: MODE_SMA; MODE_EMA; MODE_SMMA; MODE_LWMA
   MA_handle=iMA(NULL,M[m],periodMA,0,MODE_SMA,P[p]);
   while(BarsCalculated(MA_handle)<count){}
   CopyBuffer(MA_handle,0,0,count,MA);
  }


4.4. Cas №3

Dans le cas №3, les classes fonctionnant avec les indicateurs des classes de la bibliothèque standard sont utilisées.

La copie de données élément par élément est utilisée. Le calcul est effectué sur l'ensemble du tableau de données.

Modèle Résultat Meilleur résultat
MODE_SMA 0,0998 0,000140 (cas 6)
MODE_EMA 0,0997 0,000121 (cas 6)
MODE_SMMA 0,0998 0,000117 (cas 6):
MODE_LWMA 0,0998 0,0029 (cas 2 et 5)
#include <Indicators\Trend.mqh>
ENUM_TIMEFRAMES      M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE   P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      buf[];
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
CiMA        objMA;
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   if(ArrayResize(buf,count)<0) return(-1);
   ArraySetAsSeries(buf,false);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test6();
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test6()
  {
//--- Model: MODE_SMA; MODE_EMA; MODE_SMMA; MODE_LWMA
   objMA.Create(NULL,M[m],periodMA,0,MODE_SMA,P[p]);
   objMA.BuffSize(count);
   objMA.Refresh(1);
   for(int i=0;i<count;i++)
     {
      buf[i]=objMA.Main(i);
     }
  }

4.5. Cas №4

Dans le cas №4, les classes fonctionnant avec des indicateurs des classes de bibliothèque standard sont utilisées.

Le tableau du tampon indicateur est copié dans son ensemble. Le calcul est effectué sur l'ensemble du tableau de données.

Modèle Résultat Meilleur résultat
MODE_SMA 0,0996 0,000140 (cas 6)
MODE_EMA 0,0996 0,000121 (cas 6)
MODE_SMMA 0,0996 0,000117 (cas 6):
MODE_LWMA 0,0996 0,0029 (cas 2, 5)
#include <Indicators\Trend.mqh>
ENUM_TIMEFRAMES      M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE   P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      buf[];
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
CiMA        objMA;
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   if(ArrayResize(buf,count)<0) return(-1);
   ArraySetAsSeries(buf,false);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test7();
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test7()
  {
//--- Models: MODE_SMA; MODE_EMA; MODE_SMMA; MODE_LWMA
   objMA.Create(NULL,M[m],periodMA,0,MODE_SMA,P[p]);
   objMA.BuffSize(count);
   objMA.Refresh(1);
   objMA.GetData(0,count,0,buf);          
  }


4.6. Cas №5

Le test №8 est utilisé : la poignée de l'indicateur est créée à l'aide de la fonction IndicatorCreate.

Le calcul est effectué sur l'ensemble du tableau de données.
Modèle Résultat Meilleur résultat
MODE_SMA 0,0030 0,000140 (cas 6)
MODE_EMA 0,0029 0,000121 (cas 6)
MODE_SMMA 0,0029 0,000117 (cas 6):
MODE_LWMA 0,0029 0,0029 (cas 2 et 5)
ENUM_TIMEFRAMES      M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE   P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      time;
int         count=10000;
int         startGTC,endGTC;
int         m,p;
double      MA[];                // array for the iMA indicator
int         MA_handle;           // handle of the iMA indicator
MqlParam    params[];
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   ArrayResize(params,4);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test8();
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test8()
  {
//--- Model: MODE_SMA; MODE_EMA; MODE_SMMA; MODE_LWMA
//--- set ma_period
   params[0].type         =TYPE_INT;
   params[0].integer_value=periodMA;
//--- set ma_shift
   params[1].type         =TYPE_INT;
   params[1].integer_value=0;
//--- set ma_method
   params[2].type         =TYPE_INT;
   params[2].integer_value=MODE_SMA;
//--- set applied_price
   params[3].type         =TYPE_INT;
   params[3].integer_value=P[p];
//--- create MA
   MA_handle=IndicatorCreate(NULL,M[m],IND_MA,4,params);
   while(BarsCalculated(MA_handle)<count){}
   CopyBuffer(MA_handle,0,0,count,MA);
  }


4.7. Cas №6

Dans ce cas, nous avons effectué le calcul de 4 modèles : №9(SMA), №10(EMA), №11(SMMA) и №12(LWMA) en utilisant les fonctions de la bibliothèque MovingAverages.mqh (les fonctions de tampon comme iMAOnArray de MQL4) .

Le calcul est effectué sur l'ensemble du tableau de données.

Modèle Résultat Meilleur résultat
MODE_SMA 0,000140 0,000140 (cas 6)
MODE_EMA 0,000121 0,000121 (cas 6)
MODE_SMMA 0,000117 0,000117 (cas 6):
MODE_LWMA 0,00350 0,0029 (cas 2 et 5)
#include <MovingAverages.mqh>
ENUM_TIMEFRAMES         M[4]=
  {
   PERIOD_M1,
   PERIOD_M5,
   PERIOD_M15,
   PERIOD_M30
  };
ENUM_APPLIED_PRICE         P[7]=
  {
   PRICE_CLOSE,
   PRICE_OPEN,
   PRICE_HIGH,
   PRICE_LOW,
   PRICE_MEDIAN,
   PRICE_TYPICAL,
   PRICE_WEIGHTED
  };
int         periodMA;
double      buf[],arr[];
double      close[];
double      time;
int         count=10000,total;
int         startGTC,endGTC;
int         m,p;
//+------------------------------------------------------------------+
//| script program start function                                    |
//+------------------------------------------------------------------+
int OnStart()
  {
   CopyClose(_Symbol,_Period,0,count,close);
   total=ArrayCopy(arr,close);
   if(ArrayResize(buf,total)<0) return(-1);
//---
   ArraySetAsSeries(close,false);
   ArraySetAsSeries(arr,false);
   ArraySetAsSeries(buf,false);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         CopyClose(_Symbol,M[m],0,count,close);
         total=ArrayCopy(arr,close);
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test9();    // the test is here
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//---
   return(0);
  }
//+------------------------------------------------------------------+
void Test9()
  {
   SimpleMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
void Test10()
  {
   ExponentialMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
void Test11()
  {
   SmoothedMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
void Test12()
  {
   LinearWeightedMAOnBuffer(total,0,0,periodMA,arr,buf);
  }

Note: Nous avons prévu d'utiliser plusieurs types de données dans le tableau, mais pour plus de simplicité, nous n'avons utilisé qu'un seul tableau avec des données de prix de clôture (cela n'affecte pas la performance des calculs).


5. Sortie des résultats

Pour la sortie des résultats et la vérification des Moyennes Mobiles, j'ai utilisé la fonction PrintTest :

void PrintTest(const int position, const double &price[])
{
   Print("Total time [msec] ",(endGTC-startGTC));
   Print("Performance [sec] ",time);
   Print(position," - array element = ",price[position]);
}

Elle peut être appelée comme suit (la position de la barre et le tableau de données sont des paramètres de la fonction) :

//---
   ArraySetAsSeries(buf,false);
   ArraySetAsSeries(close,false);
   startGTC=GetTickCount();
//---
   for(m=0;m<=3;m++)
     {
      for(p=0;p<=6;p++)
        {
         for(periodMA=1;periodMA<=100;periodMA++)
           {
            Test();
           }
        }
     }
//---
   endGTC=GetTickCount();
   time=endGTC-startGTC;
   time=time/1000/m/p/periodMA;
//--- Output of results
   ArraySetAsSeries(buf,true);
   ArraySetAsSeries(close,true);
   PrintTest(0,buf);
   PrintTest(0,close);
//---

Notez que l'indexation des tableaux est différente avant et après les calculs.

IMPORTANT. L'indicateur AsSeries est défini comme faux durant les calculs et défini comme vrai lors de l’impression des résultats.


6. Enquêtes supplémentaires

Pour répondre à la question sur l'effet des paramètres initiaux sur la performance du calcul, quelques mesures supplémentaires ont été effectuées.

Comme nous nous en souvenons, le boîtier №6 présente la meilleure performance, nous allons donc l'utiliser.

Paramètres de test

Mode
Délai
 Période de moyenne
1
М1
144
2
М5
144
3
М15
144
4
М30
144
5
М1 21
6
М1 34
7
М1 55
8
М1 89
9
М1 233
10
М1 377
11
М1 610
12
М1 987

Tableau3 Enquêtes complémentaires

Code source des tests :

//+------------------------------------------------------------------+
//| Test_SMA                                       Model: MODE_SMA   |
//+------------------------------------------------------------------+
void Test_SMA(int periodMA,ENUM_TIMEFRAMES periodTF)
  {
   CopyClose(_Symbol,periodTF,0,count,close);
   int total=ArrayCopy(arr,close);
   SimpleMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
//| Test_EMA                                       Model: MODE_EMA   |
//+------------------------------------------------------------------+
void Test_EMA(int periodMA,ENUM_TIMEFRAMES periodTF)
  {
   CopyClose(_Symbol,periodTF,0,count,close);
   int total=ArrayCopy(arr,close);
   ExponentialMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
//| Test_SMMA                                      Model: MODE_SMMA  |
//+------------------------------------------------------------------+
void Test_SMMA(int periodMA,ENUM_TIMEFRAMES periodTF)
  {
   CopyClose(_Symbol,periodTF,0,count,close);
   int total=ArrayCopy(arr,close);
   SmoothedMAOnBuffer(total,0,0,periodMA,arr,buf);
  }
//+------------------------------------------------------------------+
//| Test_LWMA                                      Model: MODE_LWMA  |
//+------------------------------------------------------------------+
void Test_LWMA(int periodMA,ENUM_TIMEFRAMES periodTF)
  {
   CopyClose(_Symbol,periodTF,0,count,close);
   int total=ArrayCopy(arr,close);
   LinearWeightedMAOnBuffer(total,0,0,periodMA,arr,buf);
  }

Pour les tests supplémentaires, nous utiliserons le programme d'autotest, son interface utilisateur graphique est présentée à la Fig. 7.

Figure 7. Le programme d'autotest pour les tests automatisés

Figure 7. Le programme d'autotest pour les tests automatisés

Résultats: (les axes X ont une échelle de temps logarithmique)

Figure 8. Le paramètre Timeframe (Y) et la performance de calcul des Moyennes Mobiles (X)

Figure 8. Le paramètre Délai (Y) et la performance de calcul des Moyennes Mobiles (X)

Figure 9. la performance de calcul du paramètre Durée (Y) et des Moyennes Mobiles (X)

Figure 9. Le paramètre Période (Y) et la performance de calcul des Moyennes Mobiles (X)

Les conclusions des résultats d'enquêtes complémentaires:

  1. Le paramètre délai n'est pas important, il n'affecte pas la performance de calcul (voir fig. 8).
  2. La durée n'est pas un paramètre important pour la performance du calcul des Moyennes Mobiles pour les modèles SMA, EMA et SMMA. Mais en revanche, elle ralentit considérablement (de 0,00373 seconde à 0,145 seconde) les calculs pour le modèle LWMA (voir. fig. 9).


Conclusion

Le mauvais choix de l'algorithme des Moyennes Mobiles est en mesure de réduire la performance de calcul de vos programmes.


Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/106

Fichiers joints |
autotest__1.zip (10.86 KB)
Les Principes du Calcul Économique des Indicateurs Les Principes du Calcul Économique des Indicateurs
Les appels aux utilisateurs et les indicateurs techniques occupent très peu de place dans le code de programme des systèmes de trading automatisés. Souvent, il s’agit simplement de quelques lignes de code. Mais il arrive souvent ces quelques lignes de code utilisant plus de temps, qui doivent être consacrées au test de l’Expert Advisor. Par conséquent, tout ce qui est lié aux calculs de données dans un indicateur doit être considéré de manière beaucoup plus approfondie qu’il n’y paraît à première vue. Cet article en parlera précisément
Création d’un Expert Advisor, qui trade sur un certain nombre d’instruments Création d’un Expert Advisor, qui trade sur un certain nombre d’instruments
Le concept de diversification des actifs sur les marchés financiers est vieux et a toujours attiré les traders débutants. Dans cet article, l’auteur propose une approche extrêmement simple d’une élaboration d’un Expert Advisor multi-devises, pour une première introduction à cette direction des stratégies de trading.
L'utilisation de ORDER_MAGIC pour trader avec différents Expert Advisors sur un seul instrument L'utilisation de ORDER_MAGIC pour trader avec différents Expert Advisors sur un seul instrument
Cet article examine les questions du codage de l’information, en utilisant l’identification magique, ainsi que la division, l’assemblage et la synchronisation du trading automatique des différents Expert Advisors. Cet article sera intéressant pour les débutants, ainsi que pour les traders les plus expérimentés, car il traite la question des positions virtuelles, ce qui peut être utile dans l’implémentation des systèmes complexes de synchronisation d’Expert Advisors et de diverses stratégies.
Analyser  les modèles de chandeliers Analyser les modèles de chandeliers
La réalisation d'un graphique en chandeliers japonais et l'analyse des modèles de chandeliers constituent un domaine passionnant d'analyse technique. L'avantage des chandeliers est qu'ils représentent les données de sorte que vous puissiez suivre la dynamique à l'intérieur des données. Dans cet article, nous analysons les types de chandeliers, la classification des modèles de chandeliers et présentons un indicateur pouvant déterminer les modèles de chandeliers.