English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
MQL5에서 이동 평균 계산 성능 테스트

MQL5에서 이동 평균 계산 성능 테스트

MetaTrader 5 | 5 7월 2021, 15:22
83 0
Sergey Pavlov
Sergey Pavlov


소개

이동 평균의 사용은 인디케이터 및 Expert Advisors 프로그램에서 시장 시계열 분석에서 일반적인 관행입니다. 가장 널리 사용되는 가격 데이터 평활 방법입니다. 새 버전의 MQL 언어에는 수십 개의 이동 평균 알고리즘을 사용할 수 있습니다.

그게 그들 사이의 차이점입니까? 실제로 계산 속도가 특정 이동 평균 알고리즘에 의존합니까? 어떤 알고리즘이 더 빠릅니까?

MetaTrader 4에 비해 MetaTrader 5에서 이동 평균 계산 속도가 증가했습니까? 그런 질문이 많이 나옵니다. 그래서, 그들 대부분을 고려해봅시다.

물론 새로운 플랫폼의 속도는 인상적이지만 실험적으로 확인하는 것이 좋습니다.


1. 테스트 조건

계산 속도는 여러 요인에 따라 달라집니다. 따라서 다른 테스트 조건에서 이 연구의 결과로 얻은 데이터는 다를 수 있습니다. 즉, 성능의 절대 값은 다르지만 상대 값은 유사해야 합니다 (인증 플랫폼의 경우).

MQL5의 iMA 함수는 계산 결과 자체를 반환하지 않기 때문에 (인디케이터의 핸들을 반환) 다음 두 함수의 속도를 테스트합니다: iMACopyBuffer.

테스트 조건:
  • CPU: 코어 i7 965
  • 기호: "EURUSD"
  • 가격 데이터 크기: 10000 요소
  • 클라이언트 터미널: 자율의 차트의 최대 바의 수는 10000으로 설정
  • 이동 평균 모델: MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA
  • 계산 속도의 정확도는 유효 숫자 2개로 제한됩니다.
  • 이동 평균 함수의 가능한 호출 수: 7개


2. 테스트 방법

이동 평균 계산 시간을 측정하기 위해 밀리 초 단위로 작동하는 GetTickCount() 함수가 있습니다. 이 정확도로는 충분하지 않으므로 측정 품질을 개선하기 위해 몇 가지 주기를 구성해야 합니다.

그러나 동일한 계산 및 동일한 입력 데이터로 루프를 여러 번 반복하면 결과가 왜곡됩니다. 그 이유는 다음과 같습니다. iMA 함수는 클라이언트 터미널의 글로벌 캐시에 해당 기술 인디케이터의 사본을 생성합니다. 인디케이터의 복사본 (동일한 매개 변수 포함)이 이미 글로벌 캐시에 있는 경우 새 복사본이 생성되지 않고 인디케이터 복사본의 참조 카운터가 증가합니다.

즉, 전체 버퍼 인디케이터는 첫 번째 호출에서 한 번만 계산되고 모든 후속 호출에서는 준비된 값만 취하고 새 데이터만 다시 계산합니다.

따라서 인디케이터의 입력 매개 변수가 사이클 동안 고유 할 때 루프를 구성해야 합니다. 세 가지 매개 변수를 선택했습니다. 평균 기간; 기간 및 적용 가격.

매개 변수
 값의 범위
 평균 기간
 1에서 100까지
 기간
 М1, М5, М15, М30
 적용 가격
 PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED

표 1. 입력 매개 변수의 범위

7개의 서로 다른 호출 방법을 사용하여 요소가 10000개인 배열에 대한 이동 평균 값을 계산합니다 (섹션 4의 세부 정보 참조).


3. 연구 결과

표 1의 모든 결과를 결합했으며 계산 성능은 초 단위의 계산 시간 (표 1 참조)을 사용하여 추정됩니다. 이 프로그램은 100х4х7 = 2800 유형의 이동 평균을 계산하고 10,000 요소로 가격 배열의 계산 시간을 결정합니다. 단일 패스 (사이클)의 계산 시간은 총 시간을 2800으로 나눈 값과 거의 같습니다. 예를 들어 케이스 1과 SMA 모드의 경우 ~ 0,0028/2800과 같습니다.

모드
MODE_SMAMODE_EMAMODE_SMMAMODE_LWMA플랫폼
0   (see section 4.1)
0,0041 0,0040 0,0043 0,0041  MetaTrader 4
1   (섹션 4.2 참조) 0,0028 0,00023 0,00027 0,0045  MetaTrader 5
2   (섹션 4.3 참조) 0,0029 0,0029 0,0029 0,0029  MetaTrader 5
3   (섹션 4.4 참조) 0,0998 0,0997 0,0998 0,0998  MetaTrader 5
4   (섹션 4.5 참조) 0,0996 0,0996 0,0996 0,0996  MetaTrader 5
5   (섹션 4.6 참조) 0,0030 0,0029 0,0029 0,0029  MetaTrader 5
6   (섹션 4.7 참조) 0,000140 0,000121 0,000117 0,0035  MetaTrader 5

표 2. 결과

테스트 사례의 의미에 대해서는 추가로 고려할 것입니다 (4.1-4.7 절). 이동 평균 계산 성능의 전체 그림을 추정해 보겠습니다. 

이동 평균 계산 성능의 전체 그림을 추정해 보겠습니다. 이동 평균의 호출 유형은 X 축 (표 2 참조)에 표시되고 Y 축의 값은 -1을 곱한 로그 스케일로 표시되므로 값이 클수록 성능이 더 빠릅니다. 각 계산 모델 (SMA, EMA, SMMA, LWMA)은 차트의 열에 해당합니다.

그림 1. 다양한 이동 평균 알고리즘에 대한 성능 테스트 결과

그림 1. 다양한 이동 평균 알고리즘에 대한 성능 테스트 결과

이동 평균 계산의 여러 경우에 대해 계산 속도에서 상당한 차이를 볼 수 있습니다. 이게 무슨 뜻이죠? MQL5 개발자가 제공하는 이동 평균 계산의 여러 알고리즘은 계산 성능이 다릅니다. 빠른 알고리즘 (케이스 6)과 느린 방법 (케이스 3 및 4)이 있습니다. 따라서 이동 평균을 사용하는 MQL5에서 프로그램을 작성할 때 올바른 알고리즘을 선택하는 것이 필요합니다.

각 이동 평균 모델 (0-6)의 계산 시간은 다음 그림에 자세히 나와 있습니다 (표 2 참조).

그림 2. MODE_SMA 모드의 MA 계산 성능

그림 2. MODE_SMA 모드의 MA 계산 성능

그림 3. MODE_EMA 모드의 MA 계산 성능

그림 3. MODE_EMA 모드의 MA 계산 성능

그림 4. MODE_SMMA 모드의 MA 계산 성능

그림 4. MODE_SMMA 모드의 MA 계산 성능

그림 5. MODE_LWMA 모드의 MA 계산 성능

그림 5. MODE_LWMA 모드의 MA 계산 성능

MetaTrader 4와 MetaTrader 5의 두 플랫폼의 계산 성능을 비교하는 것은 흥미롭습니다. 결과는 표 2, 사례 №0 (MQL4) 및 사례 №2 (MQL5)에 나와 있습니다.

편의상 iMA 표준 인디케이터의 계산 결과를 별도의 차트와 표로 결합해보겠습니다 (그림 6 참조). 테스트 계산 시간은 Y 축에 표시됩니다.

그림 6. MetaTrader 4 и MetaTrader 5 계산 성능 비교 차트

그림 6. MetaTrader 4 и MetaTrader 5 계산 성능 비교 차트

결론:

  1. 새로운 MetaTrader 5 플랫폼은 이전 MetaTrader 4보다 40% 더 빠릅니다.
  2. SMA, EMA 및 SMMA 모델 (케이스 №6), LWMA (케이스 №2 및 №5)에서 가장 빠른 성능을 달성했습니다.
  3. 테스트 케이스의 경우 표준 인디케이터 iMA를 사용하면 다른 모델의 계산 성능이 거의 동일합니다. MovingAverages.mqh 라이브러리 함수에 대해서는 사실이 아닙니다. 모델에 따라 성능은 거의 주문 (0,00023 ~ 0,0045)만큼 다릅니다.
  4. 제시된 결과는 "콜드 스타트"에 해당하며 클라이언트 터미널의 글로벌 캐시에 미리 계산된 데이터가 없습니다.


4. 사례 연구

MQL5 개발자는 다음 표준 기술 인디케이터의 값을 가져 오는 방법을 권장합니다.

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

이 방법은 "초보자를 위한 MQL5: Expert Advisors 기술 인디케이터 사용 지침" 문서에 자세히 설명되어 있습니다.

이동 평균의 계산 성능을 테스트하려면 이벤트 (예: 새로운 틱 이벤트 등)를 기다리지 않고 모든 계산을 수행할 수 있으므로 스크립트를 사용하는 것이 좋습니다.

모든 테스트 사례에 대해 별도의 범용 프로그램을 만들 필요는 없으므로 모든 MA 계산 사례에 대해 별도의 스크립트를 만들 것입니다.

따라서 이동 평균 계산의 각 사례를 자세히 살펴 보겠습니다.


4.1. 사례  №0

이 경우 MQL4의 기술 인디케이터 iMA의 계산 성능을 측정했습니다. 계산은 MetaTrader4에서 수행되며 모든 데이터에 대해 수행됩니다.

모델결과최상의 결과
MODE_SMA 0,0041 0,000140 (사례 6)
MODE_EMA 0,0040 0,000121 (사례 6)
MODE_SMMA 0,0043 0,000117 (사례 6)
MODE_LWMA 0,0041 0,0029 (사례 2, 5)


이 경우의 코드는 다음과 같습니다 (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);
     }
  }

참고:이 코드는 MQL4로 작성 되었기 때문에 MetaTrader 5에서 작동하지 않습니다. MetaTrader 4 클라이언트 터미널에서 실행해야 합니다.


4.2. 사례 №1

이 경우, MovingAverages.mqh 라이브러리 함수를 사용하여 №1(SMA), №2(EMA), №3(SMMA) и №4(LWMA)의 4 가지 모델을 계산했습니다.

계산은 모든 데이터 배열에서 수행됩니다.

모델
 결과최상의 결과
MODE_SMA
0,0028
0,000140 (사례 6)
MODE_EMA
0,00023
0,000121 (사례 6)
MODE_SMMA
0,000270,000117 (사례 6)
MODE_LWMA
0,00450,0029 (사례 2 및 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);
     }
  }

참고. 배열에서 여러 유형의 데이터를 사용할 계획이지만 단순성을 위해 종가 데이터가 포함된 배열 하나만 사용했습니다 (계산 성능에는 영향을 주지 않음).


4.3. 사례 №2

이 경우 iMA 표준 기술 인디케이터 및 테스트 №5를 사용했습니다.

계산은 모든 데이터 배열에서 수행됩니다.

모델결과최상의 결과
MODE_SMA 0,0029 0,000140 (사례 6)
MODE_EMA 0,0029 0,000121 (사례 6)
MODE_SMMA 0,0029 0,000117 (사례 6)
MODE_LWMA 0,0029 0,0029 (사례 2 및 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. 사례 №3

№3의 경우 표준 ​​라이브러리 클래스의 인디케이터 작업 클래스가 사용됩니다.

요소 별 데이터 복사가 사용됩니다. 계산은 모든 데이터 배열에서 수행됩니다.

모델결과최상의 결과
MODE_SMA 0,0998 0,000140 (사례 6)
MODE_EMA 0,0997 0,000121 (사례 6)
MODE_SMMA 0,0998 0,000117 (사례 6)
MODE_LWMA 0,0998 0,0029 (사례 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++)
           {
            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

№4의 경우 표준 ​​라이브러리 클래스의 인디케이터로 작업하는 클래스가 사용됩니다.

인디케이터 버퍼의 배열이 전체적으로 복사됩니다. 계산은 모든 데이터 배열에서 수행됩니다.

모델결과최상의 결과
MODE_SMA 0,0996 0,000140 (사례 6)
MODE_EMA 0,0996 0,000121 (사례 6)
MODE_SMMA 0,0996 0,000117 (사례 6)
MODE_LWMA 0,0996 0,0029 (사례 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. 사례 №5

테스트 №8이 사용됩니다. 인디케이터 핸들은 IndicatorCreate 함수를 사용하여 생성됩니다.

계산은 모든 데이터 배열에서 수행됩니다.
모델결과최상의 결과
MODE_SMA 0,0030 0,000140 (사례 6)
MODE_EMA 0,0029 0,000121 (사례 6)
MODE_SMMA 0,0029 0,000117 (사례 6)
MODE_LWMA 0,0029 0,0029 (사례 2 및 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. 사례 №6

이 경우, MovingAverages.mqh 라이브러리 함수 (iMAOnArray와 같은 버퍼 함수)를 사용하여 №9(SMA), №10(EMA), №11(SMMA) и №12(LWMA) 모델의 계산을 수행했습니다. MQL4).

계산은 모든 데이터 배열에서 수행됩니다.

모델결과최상의 결과
MODE_SMA 0,000140 0,000140 (사례 6)
MODE_EMA 0,000121 0,000121 (사례 6)
MODE_SMMA 0,000117 0,000117 (사례 6)
MODE_LWMA 0,00350 0,0029 (사례 2 및 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);
  }

참고. 배열에서 여러 유형의 데이터를 사용할 계획이지만 단순성을 위해 종가 데이터가 포함된 배열 하나만 사용했습니다 (계산 성능에는 영향을 주지 않음).


5. 결과의 출력

결과 출력과 이동 평균 확인을 위해 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]);
}

다음과 같이 호출 할 수 있습니다 (바의 포지션 및 데이터 배열은 함수의 매개 변수 임).

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

배열 인덱싱은 계산 전후에 다릅니다.

IMPORTANT. AsSeries 플래그는 계산 중에 false로 설정되고 결과를 인쇄 할 때 true로 설정됩니다.


6. 추가 조사

계산 성능에 대한 초기 매개 변수의 영향에 대한 질문에 답하기 위해 몇 가지 추가 측정이 수행되었습니다.

기억하고 있듯이 №6 케이스의 성능이 가장 좋으므로 사용하겠습니다.

테스트 매개 변수:

모드
기간
 평균 기간
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

표 3. 추가 조사

테스트의 소스 코드:

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

추가 테스트를 위해 자동 테스트 프로그램을 사용할 것입니다. 그래픽 사용자 인터페이스는 그림 7에 나와 있습니다.

그림 7. Aurtomated 테스트를 위한 자동 테스트 프로그램

그림 7. 자동 테스트 자동 테스트 프로그램

결과: (X 축은 로그 시간 척도를 가짐)

그림 8. Timeframe 매개 변수 (Y) 및 이동 평균 계산 성능 (X)

그림 8. Timeframe 매개 변수 (Y) 및 이동 평균 계산 성능 (X)

그림 9. 기간 매개 변수 (Y) 및 이동 평균 계산 성능 (X)

그림 9. 기간 매개 변수 (Y) 및 이동 평균 계산 성능 (X)

추가 조사 결과의 결론:

  1. timeframe 매개 변수는 중요하지 않으며 계산 성능에 영향을 주지 않습니다 (그림 8 참조)
  2. 기간은 SMA, EMA 및 SMMA 모델의 이동 평균 계산 성능에 중요한 매개 변수가 아닙니다. 그러나 대조적으로 LWMA 모델에 대한 계산 속도가 크게 (0,00373 초에서 0,145 초로) 느려집니다 (그림 9 참조).


결론

이동 평균 알고리즘을 잘못 선택하면 프로그램의 계산 성능이 저하 될 수 있습니다.


MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/106

파일 첨부됨 |
autotest__1.zip (10.86 KB)
예시를 통해 보는 MQL5 의 OOP: 프로세싱 경고와 에러 코드 예시를 통해 보는 MQL5 의 OOP: 프로세싱 경고와 에러 코드
이 문서에서는 매매 서버 리턴 코드 작업을 위한 클래스를 생성하는 예와 MQL 프로그램 실행 중에 발생하는 모든 오류에 대해 설명합니다. 이 문서를 다 읽고나면 당신은 MQL5로 클래스나 객체를 어떻게 다뤄야하는지 알게될 것입니다. 또한 이 도구는 오류를 처리하는 데 편리한 도구이며 특정 필요에 따라 이 도구를 추가로 변경할 수 있습니다.
여러 상품을 거래하는 Expert Advisor 생성 여러 상품을 거래하는 Expert Advisor 생성
금융 시장에서 자산 다각화의 개념은 꽤 오래된 것인데 항상 초보 트레이더를 끌어 들였습니다. 이 글에서 저자는 이러한 거래 전략 방향에 대한 초기 소개를 위해 다중 통화 Expert Advisor의 구성에 대한 최대한 간단한 접근 방식을 제안합니다.
인디케이터의 경제적 계산 원칙 인디케이터의 경제적 계산 원칙
사용자 및 기술 인디케이터에 대한 호출은 자동 거래 시스템의 프로그램 코드에서 매우 적은 공간을 차지합니다. 종종 단순히 몇 줄의 코드 일뿐입니다. 그러나 가장 많은 시간을 사용하는 몇 줄의 코드로 Expert Advisor를 테스트하는 데 소비해야 하는 경우가 종종 있습니다. 따라서 인디케이터 내 데이터 계산과 관련된 모든 것은 언뜻 보기 보다 훨씬 더 철저히 고려되어야 합니다. 이 글은 이것에 대해 정확하게 이야기 할 것입니다.
캔들스틱 패턴 분석 캔들스틱 패턴 분석
일본 캔들스틱 차트의 구성과 캔들스틱 패턴 분석은 놀라운 기술적 분석 영역을 구성합니다. 캔들스틱의 장점은 데이터 내부의 역학을 추적 할 수 있는 방식으로 데이터를 표현한다는 것입니다. 이 글에서는 캔들스틱 유형, 캔들스틱 패턴 분류를 분석하고 캔들스틱 패턴을 결정할 수 있는 인디케이터를 제시합니다.