Русский 中文 Español Deutsch 日本語 Português 한국어 Français Italiano Türkçe
Testing Performance of Moving Averages Calculation in MQL5

Testing Performance of Moving Averages Calculation in MQL5

MetaTrader 5Examples | 23 July 2010, 10:04
10 364 0
Sergey Pavlov
Sergey Pavlov


Introduction

The use of Moving Averages is a common practice in analysis of market time series, in indicators and Expert Advisors programming. It's the most popular price data smoothing method. In new version of MQL language there is a dozen of Moving Average algorithms are available.

That's the difference between them? Really, does the calculation speed dependent on certain algorithm of Moving Averages? Which algorithm is faster?

Does the calculation speed of Moving Averages has increased in MetaTrader 5 compared with MetaTrader 4? There is a lot of such questions appear. So, let's consider most of them.

Of course, the speed of a new platform is impressive, but it's better to check it experimentally.


1. Testing conditions

The calculation speed is dependent on many factors. Therefore, the data that were obtained as a results of this research, in other testing conditions would be different. In other words, the absolute values of performance will be different, but relative values should be similar (for a certiain platform).

Because of the fact that the iMA function in MQL5 doesn't return the calculation results itself (it returns an indicator's handle), we will test the speed of two functions: iMA and CopyBuffer.

Testing conditions:
  • CPU: Core i7 965
  • Symbol: "EURUSD"
  • Price data size: 10000 elements
  • Client terminal: autonomous, the maximum number of bars in the chart is set to 10000
  • Moving average models: MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA
  • The accuracy of calculation speed is limited to two significant digits
  • The possible number of calls of the Moving Averages functions: 7


2. How we tested

To measure the time of the moving averages calculation we have the GetTickCount() function, which operates in milliseconds. This accuracy is not enough, so we need to organize some cycles to improve the quality of measurements.

However, if we will repeat the loop many times with the same calculation and same input data, the results will be distorted. The reason of this fact is the following: the iMA function creates a copy of the corresponding technical indicator in the global cache of the client terminal. If the copy of an indicator ( with the same parameters) is already present in the global cache, the new copy is not created, the reference counter of the indicator's copy is increased.

In other words, the entire buffer indicator is calculated just once at the first call, and at all subsequent calls it just takes the ready values, it recalculates only the new data.

Therefore the loop should be organized the way, when input parameters of the indicator are unique during the cycle. We have selected three such parameters: averaging period; timeframe and applied price.

Parameter
 Range of the values
 Averaging period
 from 1 to 100
 Timeframe
 М1, М5, М15, М30
 Applied price
 PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED

Table 1. The ranges of input parameters

We will calculate the values of moving average for the array with 10000 elements using the seven different call methods (see details in section 4).


3. The results of the study

We have combined all results in Table 1, the calculation performance is estimated using the calculation time (see table 1) in seconds. The program calculates 100х4х7=2800 types of moving averages, and we determine the calculation time for the price array with 10 000 elements. The calculation time of the single pass (cycle) is approximately equal to total time, divided by 2800. For example, for the case 1 and SMA mode it equal to ~ 0,0028/2800.

Mode
MODE_SMAMODE_EMAMODE_SMMAMODE_LWMAPlatform
0   (see section 4.1)
0,0041 0,0040 0,0043 0,0041  MetaTrader 4
1   (see section 4.2) 0,0028 0,00023 0,00027 0,0045  MetaTrader 5
2   (see section 4.3) 0,0029 0,0029 0,0029 0,0029  MetaTrader 5
3   (see section 4.4) 0,0998 0,0997 0,0998 0,0998  MetaTrader 5
4   (see section 4.5) 0,0996 0,0996 0,0996 0,0996  MetaTrader 5
5   (see section 4.6) 0,0030 0,0029 0,0029 0,0029  MetaTrader 5
6   (see section 4.7) 0,000140 0,000121 0,000117 0,0035  MetaTrader 5

Table 2. The results

The meaning of testing cases will be considered further (sections 4.1-4.7). Let's estimate the whole picture of calculation performance of Moving Average. 

For convience, the results are presented at charts (see figures 1-5). The calling type of Moving Average is presented at X axes (see table 2), the values at Y axes are presented in logarithmic scale multiplied by -1, so the larger values means faster performance. Each of the calculation model (SMA, EMA, SMMA, LWMA) corresponds to a column on the chart.

Figure.1 The performance test results for different Moving Average algorithms

Figure 1. The performance test results for different Moving Average algorithms

One can see a significant difference in calculation speed for the different cases of the Moving Averages calculation. What does it mean? The several algorithms of Moving Averages calculation, provided by MQL5 developers have different calculation performance: there is a fast algorithm (case 6) and slower methods (cases 3 and 4). So, it's necessary to choose the correct algorithms when writing programs in MQL5, which uses Moving Averages.

The calculation time of each Moving Averages models (0-6) is presented in details on the following figures, see table 2.

Figure 2. The MA calculation performance of the MODE_SMA mode

Figure 2. The MA calculation performance of the MODE_SMA mode

Figure 3. The MA calculation performance of the MODE_EMA mode

Figure 3. The MA calculation performance of the MODE_EMA mode

Figure 4. The MA calculation performance of the MODE_SMMA mode

Figure 4. The MA calculation performance of the MODE_SMMA mode

Figure 5. The MA calculation performance of the MODE_LWMA mode

Figure 5. The MA calculation performance of the MODE_LWMA mode

It's interesting to compare the calculation performance of two platforms: MetaTrader 4 and MetaTrader 5. The results are presented in Table 2, case №0 (MQL4) and case №2 (MQL5).

For convience, let's combine the calculation results of iMA standard indicator into a separate chart and table (see fig. 6). The calculation time of the test is presented at Y axes.

Figure 6. Comparative chart of MetaTrader 4 и MetaTrader 5 calculation performance

Figure 6. Comparative chart of MetaTrader 4 и MetaTrader 5 calculation performance

Conclusions:

  1. The new MetaTrader 5 platform is 40% faster than previous  MetaTrader 4.
  2. The fastest perfromance has been achieved for the SMA, EMA, and SMMA models (case №6), for LWMA (cases №2 and №5).
  3. For test cases, when the standard indicator iMA is used, the calculation performance of different models is practically identical. It's not true for the MovingAverages.mqh library functions. For different models the performance differ by almost an order (0,00023~0,0045).
  4. The results presented is corresponds to "cold start", there isn't any precalculated data in the global cache of the client terminal.


4. Case Studies

The MQL5 developers recommend the following method for getting the values of standard technical indicators:

//---- 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
  }

This method is described in details in the article "MQL5 for Newbies: Guide to Using Technical Indicators in Expert Advisors".

For testing of the calculation performance of moving averages, it's beter to use the script, because it's able perform all the calculations without waiting of the events (for example, new tick event, etc.).

It isn't necessary to create a separate universal program for all test cases, therefore we will create a separate script for every case of MA calculation.

So, let's consider in details each of the cases of Moving Average calculations.


4.1. Case  №0

In this case we measured the calculation performance of technical indicator iMA of MQL4. The calculations is perfomed in MetaTrader4 and carried out on all the data.

ModelResultBest result
MODE_SMA 0,0041 0,000140 (case 6)
MODE_EMA 0,0040 0,000121 (case 6)
MODE_SMMA 0,0043 0,000117 (case 6)
MODE_LWMA 0,0041 0,0029 (cases 2, 5)


The code of this case is the following (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: This code will not work in MetaTrader 5, because it written in MQL4. It should be executed at MetaTrader 4 client terminal.


4.2. Case №1

In this case we have performed calculation of 4 models: №1(SMA), №2(EMA), №3(SMMA) и №4(LWMA) using the MovingAverages.mqh library functions.

The calculation is carried out on all the data array.

Model
 ResultBest result
MODE_SMA
0,0028
0,000140 (case 6)
MODE_EMA
0,00023
0,000121 (case 6)
MODE_SMMA
0,000270,000117 (case 6)
MODE_LWMA
0,00450,0029 (cases 2 and 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. We have planned to use the several types of data in the array, but for the simplicity, we have used only one array with close prices data (it doesn't affect on the performance of calculations).


4.3. Case №2

In this case we have used the iMA standard technical indicator and test №5.

The calculation is carried out on all the data array.

ModelResultBest result
MODE_SMA 0,0029 0,000140 (case 6)
MODE_EMA 0,0029 0,000121 (case 6)
MODE_SMMA 0,0029 0,000117 (case 6)
MODE_LWMA 0,0029 0,0029 (cases 2 and 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. Case №3

In case №3 the classes working with indicators of the Standard library classes are used.

The elementwise data copying is used. The calculation is carried out on all the data array.

ModelResultBest result
MODE_SMA 0,0998 0,000140 (case 6)
MODE_EMA 0,0997 0,000121 (case 6)
MODE_SMMA 0,0998 0,000117 (case 6)
MODE_LWMA 0,0998 0,0029 (cases 2 and 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. Case №4

In case №4 the classes working with indicators of the Standard library classes are used.

The indicator buffer's array is copied as a whole. The calculation is carried out on all the data array.

ModelResultBest result
MODE_SMA 0,0996 0,000140 (case 6)
MODE_EMA 0,0996 0,000121 (case 6)
MODE_SMMA 0,0996 0,000117 (case 6)
MODE_LWMA 0,0996 0,0029 (cases 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. Case №5

The test №8 is used: the indicator handle is created using the IndicatorCreate function.

The calculation is carried out on all the data array.
ModelResultBest result
MODE_SMA 0,0030 0,000140 (case 6)
MODE_EMA 0,0029 0,000121 (case 6)
MODE_SMMA 0,0029 0,000117 (case 6)
MODE_LWMA 0,0029 0,0029 (cases 2 and 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. Case №6

In this case we have performed calculation of 4 models: №9(SMA), №10(EMA), №11(SMMA) и №12(LWMA) using the MovingAverages.mqh library functions (the buffer functions like iMAOnArray from MQL4).

The calculation is carried out on all the data array.

ModelResultBest result
MODE_SMA 0,000140 0,000140 (case 6)
MODE_EMA 0,000121 0,000121 (case 6)
MODE_SMMA 0,000117 0,000117 (case 6)
MODE_LWMA 0,00350 0,0029 (cases 2 and 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. We have planned to use the several types of data in the array, but for the simplicity, we have used only one array with close prices data (it doesn't affect on the performance of calculations).


5. Output of the Results

For the output of the results and checking of the moving averages, I used the PrintTest function:

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

It can be called, as follows (the bar position and data array are parameters of the function):

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

Note, that array indexing are differ before and after the calculations.

IMPORTANT. The AsSeries flag is set to false during the calculations and it set to true when printing the results.


6. Additional Investigations

To answer the question about the effect of initial parameters on the performance of calculation, some additional measurements have done.

As we remember, the case №6 has best performance, so we will use it.

Testing parameters:

Mode
Timeframe
 Averaging period
1
М1
144
2
М5
144
3
М15
144
4
М30
144
5
М121
6
М134
7
М155
8
М189
9
М1233
10
М1377
11
М1610
12
М1987

Table 3. Additional investigations

Source code of the 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);
  }

For the additional tests we will use the autotest program, its graphic user interface is presented at Fig. 7.

Figure 7. The autotest program for the aurtomated testing

Figure 7. The autotest program for the aurtomated testing

Results: (the X axes has a logarithmic time scale)

Figure 8. The Timeframe parameter (Y) and Moving Averages calculation performance (X)

Figure 8. The Timeframe parameter (Y) and Moving Averages calculation performance (X)

Figure 9. The Period parameter (Y) and Moving Averages calculation performance (X)

Figure 9. The Period parameter (Y) and Moving Averages calculation performance (X)

The conclusions of the results of additional investigations:

  1. The timeframe parameter isn't important, it doesn't affect on the calculation performance (see fig. 8).
  2. The period isn't important parameter for the performance of moving averages calculation for the models  SMA, EMA and SMMA. But in contrast, it significantly (from 0,00373 seconds to 0,145 seconds) slows the calculations for the LWMA model (see fig. 9).


Conclusion

The incorrect choice of the moving averages algorithm is able to reduce calculation performance of your programs.


Translated from Russian by MetaQuotes Ltd.
Original article: https://www.mql5.com/ru/articles/106

Attached files |
autotest__1.zip (10.86 KB)
How to Write an Indicator on the Basis of Another Indicator How to Write an Indicator on the Basis of Another Indicator
In MQL5 you can write an indicator both from a scratch and on the basis of another already existing indicator, in-built in the client terminal or a custom one. And here you also have two ways - to improve an indicator by adding new calculations and graphical styles to it , or to use an indicator in-built in the client terminal or a custom one via the iCustom() or IndicatorCreate() functions.
Processing of trade events in Expert Advisor using the OnTrade() function Processing of trade events in Expert Advisor using the OnTrade() function
MQL5 gave a mass of innovations, including work with events of various types (timer events, trade events, custom events, etc.). Ability to handle events allows you to create completely new type of programs for automatic and semi-automatic trading. In this article we will consider trade events and write some code for the OnTrade() function, that will process the Trade event.
Interview with Nikolay Kositsin: multicurrency EA are less risky (ATC 2010) Interview with Nikolay Kositsin: multicurrency EA are less risky (ATC 2010)
Nikolay Kositsin has told us about his developments. He believes multicurrency Expert Advisors are a promising direction; and he is an experienced developer of such robots. At the championships, Nikolay participates only with multicurrency EAs. His Expert Advisor was the only multicurrency EA among the prize winners of all the ATC contests.
The Use of ORDER_MAGIC for Trading with Different Expert Advisors on a Single Instrument The Use of ORDER_MAGIC for Trading with Different Expert Advisors on a Single Instrument
This article considers the questions of information coding, using the magic-identification, as well as the division, assembly, and synchronization of automatic trading of different Expert Advisors. This article will be interesting to beginners, as well as to more experienced traders, because it tackles the question of virtual positions, which can be useful in the implementation of complex systems of synchronization of Expert Advisors and various strategies.