English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5

Test delle Prestazioni del Calcolo delle Medie Mobili in MQL5

MetaTrader 5Esempi | 16 dicembre 2021, 10:36
185 0
Sergey Pavlov
Sergey Pavlov


Introduzione

L'uso delle Medie Mobili è una pratica comune nell'analisi delle time serie di mercato, negli indicatori e nella programmazione degli Expert Advisor. È il metodo più popolare dello smoothing dei dati sui prezzi. Nella nuova versione del linguaggio MQL sono disponibili una dozzina di algoritmi Moving Average.

Questa è la differenza tra loro? Davvero, la velocità di calcolo dipende da un determinato algoritmo delle Medie Mobili? Quale algoritmo è più veloce?

La velocità di calcolo delle Medie Mobili è aumentata in MetaTrader 5 rispetto a MetaTrader 4? Tante domande simili appaiono. Quindi, consideriamo la maggior parte di loro.

Certo, la velocità di una nuova piattaforma è impressionante, ma è meglio verificarla sperimentalmente.


1. Condizioni di prova

La velocità di calcolo dipende da molti fattori. Pertanto, i dati che sono stati ottenuti a seguito di questa ricerca, sarebbero diversi in altre condizioni di test. In altre parole, i valori assoluti delle prestazioni saranno diversi, ma i valori relativi dovrebbero essere simili (per una determinata piattaforma).

A causa del fatto che la funzionei MA in MQL5 non restituisce i risultati del calcolo stesso (restituisce l'handle di un indicatore), testeremo la velocità di due funzioni: iMA e CopyBuffer.

Condizioni di prova:
  • CPU: Core i7 965
  • Simbolo: "EURUSD"
  • Dimensione dati prezzo: 10000 elementi
  • Terminale client: autonomo, il numero massimo di barre nel chart è fissato a 10000
  • Modelli di media mobile: MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA
  • La precisione della velocità di calcolo è limitata a due cifre significative
  • Il numero possibile di chiamate delle funzioni delle Medie Mobili: 7


2. Come abbiamo effettuato il test

Per misurare il tempo del calcolo delle medie mobili abbiamo la funzione GetTickCount(), che opera in millisecondi. Questa precisione non è sufficiente, quindi è necessario organizzare alcuni cicli per migliorare la qualità delle misurazioni.

Tuttavia, se ripeteremo il ciclo molte volte con lo stesso calcolo e gli stessi dati di input, i risultati saranno distorti. La ragione di questo fatto è la seguente: la funzione iMA crea una copia dell'indicatore tecnico corrispondente nella cache globale del terminale client. Se la copia di un indicatore (con gli stessi parametri) è già presente nella cache globale, la nuova copia non viene creata, viene incrementato il contatore di riferimento della copia dell'indicatore.

In altre parole, l'intero indicatore del buffer viene calcolato solo una volta alla prima chiamata, e a tutte le chiamate successive prende solo i valori pronti, ricalcola solo i nuovi dati.

Pertanto il ciclo dovrebbe essere organizzato nel modo in cui i parametri di input dell'indicatore sono unici durante il ciclo. Abbiamo selezionato tre di questi parametri: periodo della media; timeframe e prezzo applicato.

Parametro
 Gamma dei valori
 Periodo della media
 da 1 a 100
 Timeframe
 М1, М5, М15, М30
 Prezzo applicato
 PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED

Tabella 1. Le gamme dei parametri di input

Calcoleremo i valori della media mobile per l'array con 10000 elementi utilizzando i sette diversi metodi di chiamata (vedi dettagli nella sezione 4).


3. I risultati dello studio

Abbiamo unito tutti i risultati nella tabella 1, le prestazioni di calcolo sono stimate utilizzando il tempo di calcolo (vedi tabella 1) in secondi. Il programma calcola 100х4х7=2800 tipi di medie mobili e determiniamo il tempo di calcolo per l'array dei prezzi con 10.000 elementi. Il tempo di calcolo del singolo passaggio (ciclo) è approssimativamente uguale al tempo totale, diviso per 2800. Ad esempio, per il caso 1 e la modalità SMA è pari a ~ 0,0028/2800.

Modalità
MODE_SMA MODE_EMA MODE_SMMA MODE_LWMA Piattaforma
0 (vedi sezione 4.1)
0,0041 0,0040 0,0043 0,0041  MetaTrader 4
1 (vedi sezione 4.2) 0,0028 0,00023 0,00027 0,0045  MetaTrader 5
2 (vedi sezione 4.3) 0,0029 0,0029 0,0029 0,0029  MetaTrader 5
3 (vedi paragrafo 4.4) 0,0998 0,0997 0,0998 0,0998  MetaTrader 5
4 (vedi sezione 4.5) 0,0996 0,0996 0,0996 0,0996  MetaTrader 5
5 (vedi sezione 4.6) 0,0030 0,0029 0,0029 0,0029  MetaTrader 5
6 (vedi sezione 4.7) 0,000140 0,000121 0,000117 0,0035  MetaTrader 5

Tabella 2 I risultati

Il significato dei casi dei test sarà considerato ulteriormente (sezioni 4.1-4.7). Stimiamo l'intero quadro delle prestazioni di calcolo della Media Mobile. 

Per comodità, i risultati sono presentati sotto forma di grafici (vedi figure 1-5). Il tipo di chiamata di Moving Average è presentato sugli assi X (vedi tabella 2), i valori sugli assi Y sono presentati in scala logaritmica moltiplicata per -1, quindi i valori più grandi indicano le prestazioni più veloci. Ciascuno dei modelli di calcolo (SMA, EMA, SMMA, LWMA) corrisponde a una colonna del grafico.

Figura.1 I risultati del test delle prestazioni per diversi algoritmi della Media Mobile

Figura 1. I risultati del test delle prestazioni per diversi algoritmi della Media Mobile

Si può notare una differenza significativa nella velocità di calcolo per i diversi casi del calcolo delle Medie Mobili. Cosa significa? I diversi algoritmi di calcolo delle Medie Mobili, forniti dagli sviluppatori MQL5, hanno prestazioni di calcolo differenti: c'è un algoritmo veloce (caso 6) e metodi più lenti (casi 3 e 4). Quindi, è necessario scegliere gli algoritmi corretti quando si scrivono programmi in MQL5, che utilizza le Medie Mobili.

Il tempo di calcolo di ciascun modello delle Medie Mobili (0-6) è presentato in dettaglio nelle figure seguenti, vedere la tabella 2.

Figura 2. Le prestazioni di calcolo MA della modalità MODE_SMA

Figura 2. Le prestazioni di calcolo MA della modalità MODE_SMA

Figura 3. Le prestazioni di calcolo MA della modalità MODE_EMA

Figura 3. Le prestazioni di calcolo MA della modalità MODE_EMA

Figura 4. Le prestazioni di calcolo MA della modalità MODE_SMMA

Figura 4. Le prestazioni di calcolo MA della modalità MODE_SMMA

Figura 5. Le prestazioni di calcolo MA della modalità MODE_LWMA

Figura 5. Le prestazioni di calcolo MA della modalità MODE_LWMA

È interessante confrontare le prestazioni di calcolo di due piattaforme: MetaTrader 4 e MetaTrader 5. I risultati sono presentati nella Tabella 2, caso №0 (MQL4) e caso №2 (MQL5).

Per comodità, uniamo i risultati del calcolo dell'indicatore standard iMA in un grafico e una tabella separati (vedi fig. 6). Il tempo di calcolo del test è presentato sugli assi Y.

Figura 6. Grafico comparativo di MetaTrader 4 e Prestazioni di calcolo MetaTrader 5

Figura 6. Grafico comparativo di MetaTrader 4 e prestazioni di calcolo MetaTrader 5

Conclusioni:

  1. La nuova piattaforma MetaTrader 5 è più veloce del 40% rispetto alla precedente MetaTrader 4.
  2. La prestazione più veloce è stata ottenuta per i modelli SMA, EMA e SMMA (caso №6), per LWMA (casi №2 e №5).
  3. Per i casi di test, quando viene utilizzato l'indicatore standard iMA, le prestazioni di calcolo dei diversi modelli sono praticamente identiche. Non è lo stesso per le funzioni della libreria MovingAverages.mqh. Per i diversi modelli le prestazioni differiscono di quasi un ordine (0.00023~0,0045).
  4. I risultati presentati corrispondono a "cold start", non ci sono dati precalcolati nella cache globale del client terminal.


4. Casi Studio

Gli sviluppatori MQL5 consigliano il seguente metodo per ottenere i valori degli indicatori tecnici 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
  }

Questo metodo è descritto in dettaglio nell'articolo "MQL5 for Newbies: Guide to Using Technical Indicators in Expert Advisors".

Per testare le prestazioni di calcolo delle medie mobili, è meglio utilizzare lo script, perché è in grado di eseguire tutti i calcoli senza attendere gli eventi (ad esempio, nuovo evento tick, ecc.).

Non è necessario creare un programma universale separato per tutti i casi di test, quindi creeremo uno script separato per ogni caso di calcolo MA.

Quindi, consideriamo in dettaglio ciascuno dei casi di calcolo della Media Mobile.


4.1. Caso №0

In questo caso abbiamo misurato le prestazioni di calcolo dell'indicatore tecnico iMA di MQL4. I calcoli vengono eseguiti in MetaTrader4 ed eseguiti su tutti i dati.

Modello Risultato Miglior risultato
MODE_SMA 0,0041 0,000140 (caso 6)
MODE_EMA 0,0040 0,000121 (caso 6)
MODE_SMMA 0,0043 0,000117 (caso 6)
MODE_LWMA 0,0041 0,0029 (casi 2, 5)


Il codice di questo caso è il seguente (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);
     }
  }

Nota: Questo codice non funzionerà in MetaTrader 5, perché è scritto in MQL4. Dovrebbe essere eseguito sul terminale client MetaTrader 4.


4.2. Caso №1

In questo caso abbiamo eseguito il calcolo di 4 modelli: №1(SMA), №2(EMA), 3(SMMA) e №4(LWMA) utilizzando le funzioni della libreria MovingAverages.mqh.

Il calcolo viene eseguito su tutta la matrice di dati.

Modello
 Risultato Miglior risultato
MODE_SMA
0,0028
0,000140 (caso 6)
MODE_EMA
0,00023
0,000121 (caso 6)
MODE_SMMA
0,00027 0,000117 (caso 6)
MODE_LWMA
0,0045 0,0029 (casi 2 e 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);
     }
  }

Nota.Abbiamo deciso di utilizzare i diversi tipi di dati nell’array ma per semplicità abbiamo utilizzato un solo array con i dati sui prezzi di chiusura (non influisce sull'esecuzione dei calcoli).


4.3. Caso №2

In questo caso abbiamo utilizzato l'indicatore tecnico standard iMA e il test №5.

Il calcolo viene eseguito su tutta la matrice di dati.

Modello Risultato Miglior risultato
MODE_SMA 0,0029 0,000140 (caso 6)
MODE_EMA 0,0029 0,000121 (caso 6)
MODE_SMMA 0,0029 0,000117 (caso 6)
MODE_LWMA 0,0029 0,0029 (casi 2 e 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. Caso №3

Nel caso №3 vengono utilizzate le classi che lavorano con gli indicatori delle classi della libreria Standard.

Viene utilizzata la copia dei dati elementwise. Il calcolo viene eseguito su tutta la matrice di dati.

Modello Risultato Miglior risultato
MODE_SMA 0,0998 0,000140 (caso 6)
MODE_EMA 0,0997 0,000121 (caso 6)
MODE_SMMA 0,0998 0,000117 (caso 6)
MODE_LWMA 0,0998 0,0029 (casi 2 e 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. Caso №4

Nel caso №4 vengono utilizzate le classi che lavorano con gli indicatori delle classi della libreria Standard.

L'array del buffer dell'indicatore viene copiato nel suo insieme. Il calcolo viene eseguito su tutta la matrice di dati.

Modello Risultato Miglior risultato
MODE_SMA 0,0996 0,000140 (caso 6)
MODE_EMA 0,0996 0,000121 (caso 6)
MODE_SMMA 0,0996 0,000117 (caso 6)
MODE_LWMA 0,0996 0,0029 (casi 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. Caso №5

Viene utilizzato il test №8: l'handle dell'indicatore viene creato utilizzando la funzione IndicatorCreate.

Il calcolo viene eseguito su tutta la matrice di dati.
Modello Risultato Miglior risultato
MODE_SMA 0,0030 0,000140 (caso 6)
MODE_EMA 0,0029 0,000121 (caso 6)
MODE_SMMA 0,0029 0,000117 (caso 6)
MODE_LWMA 0,0029 0,0029 (casi 2 e 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. Caso 6

In questo caso abbiamo eseguito il calcolo di 4 modelli: №9(SMA), №10(EMA), №11(SMMA) e №12(LWMA) utilizzando le funzioni della libreria MovingAverages.mqh (il buffer funziona come iMAOnArray da MQL4) .

Il calcolo viene eseguito su tutta la matrice di dati.

Modello Risultato Miglior risultato
MODE_SMA 0,000140 0,000140 (caso 6)
MODE_EMA 0,000121 0,000121 (caso 6)
MODE_SMMA 0,000117 0,000117 (caso 6)
MODE_LWMA 0,00350 0,0029 (casi 2 e 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);
  }

Nota.Abbiamo pianificato di utilizzare i diversi tipi di dati nell'array, ma per semplicità abbiamo utilizzato un solo array con i dati sui prezzi di chiusura (non influisce sulle prestazioni dei calcoli).


5. Output dei Risultati

Per l'output dei risultati e la verifica delle medie mobili, ho utilizzato la funzione 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]);
}

Può essere chiamato, come segue (la posizione della barra e l'array dei dati sono parametri della funzione):

//---
   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);
//---

Si noti che l'indicizzazione dell'array è diversa prima e dopo i calcoli.

IMPORTANTE. Il flag AsSeries è impostato su false durante i calcoli e su true durante la stampa dei risultati.


6. Ulteriori Analisi

Per rispondere alla domanda sull'effetto dei parametri iniziali sulle prestazioni di calcolo, sono state effettuate alcune misurazioni aggiuntive.

Come ricordiamo, il caso №6 ha le migliori prestazioni, quindi lo useremo.

Test parametri

Modalità
Timeframe
 Periodo della media
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

Tabella 3. Ulteriori analisi

Codice sorgente dei test:

//+------------------------------------------------------------------+
//| 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);
  }

Per i test aggiuntivi utilizzeremo il programma di autotest, la sua interfaccia utente grafica è presentata nella Fig. 7.

Figura 7. Il programma di autotest per il test automatizzato

Figura 7. Il programma di autotest per i test automatizzati

Risultati: (l'asse X ha una scala temporale logaritmica)

Figura 8. Il parametro Timeframe (Y) e le prestazioni di calcolo delle Medie Mobili (X)

Figura 8. Il parametro Timeframe (Y) e le prestazioni di calcolo delle Medie Mobili (X)

Figura 9. Il parametro Period (Y) e le prestazioni di calcolo delle Medie Mobili (X) Figura 9.

Figura 9. Il parametro Period (Y) e le prestazioni di calcolo delle Medie Mobili (X)

Le conclusioni dei risultati di ulteriori analisi:

  1. Il parametro timeframe non è importante, non influisce sulle prestazioni di calcolo (vedi fig. 8).
  2. Il periodo non è un parametro importante per l'esecuzione del calcolo delle medie mobili per i modelli SMA, EMA e SMMA. Ma al contrario, rallenta significativamente i calcoli (da 0,00373 secondi a 0,145 secondi) per il modello LWMA (vedi fig. 9).


Conclusione

La scelta errata dell'algoritmo delle medie mobili è in grado di ridurre le prestazioni di calcolo dei tuoi programmi.


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/106

File allegati |
autotest__1.zip (10.86 KB)
I Principi del Calcolo Economico degli Indicatori I Principi del Calcolo Economico degli Indicatori
Le chiamate all'utente e gli indicatori tecnici occupano pochissimo spazio nel codice del programma dei sistemi di trading automatizzati. Spesso si tratta semplicemente di poche righe di codice. Ma capita spesso che siano queste poche righe di codice a impiegare la maggior parte del tempo, che deve essere speso per testare l'Expert Advisor. Pertanto, tutto ciò che è correlato ai calcoli dei dati all'interno di un indicatore, deve essere considerato molto attentamente di quanto sembrerebbe a prima vista. In questo articolo si parlerà proprio di questo.
Creazione di un Expert Advisor, che fa Trading su una Serie di Strumenti Creazione di un Expert Advisor, che fa Trading su una Serie di Strumenti
Il concetto di diversificazione delle attività sui mercati finanziari è tranquillo e ha sempre attratto i trader principianti. In questo articolo, l'autore propone un approccio estremamente semplice alla costruzione di un Expert Advisor multi-valuta, per una prima introduzione a questa direzione delle strategie di trading.
L'Uso di ORDER_MAGIC per il Trading con Diversi Expert Advisor su un Singolo Strumento L'Uso di ORDER_MAGIC per il Trading con Diversi Expert Advisor su un Singolo Strumento
Questo articolo considera le questioni della codifica delle informazioni, utilizzando l'identificazione magica, nonché la divisione, l'assemblaggio e la sincronizzazione del trading automatico di diversi Expert Advisor. Questo articolo sarà interessante per i principianti, così come per i trader più esperti, perché affronta la questione delle posizioni virtuali, che possono essere utili nell'implementazione di complessi sistemi di sincronizzazione di Expert Advisor e varie strategie.
Analizzare i Modelli di Candele Analizzare i Modelli di Candele
La costruzione del grafico a candele giapponesi e l'analisi dei modelli di candele costituiscono un'area straordinaria dell’analisi tecnica. Il vantaggio dei modelli di candele è che rappresentano i dati in modo tale da poter tenere traccia delle dinamiche all'interno dei dati. In questo articolo analizziamo i tipi di candele, la classificazione dei modelli di candele e presentiamo un indicatore in grado di determinare queste ultime.