MQL5에서 이동 평균 계산 성능 테스트
소개
이동 평균의 사용은 인디케이터 및 Expert Advisors 프로그램에서 시장 시계열 분석에서 일반적인 관행입니다. 가장 널리 사용되는 가격 데이터 평활 방법입니다. 새 버전의 MQL 언어에는 수십 개의 이동 평균 알고리즘을 사용할 수 있습니다.
그게 그들 사이의 차이점입니까? 실제로 계산 속도가 특정 이동 평균 알고리즘에 의존합니까? 어떤 알고리즘이 더 빠릅니까?
MetaTrader 4에 비해 MetaTrader 5에서 이동 평균 계산 속도가 증가했습니까? 그런 질문이 많이 나옵니다. 그래서, 그들 대부분을 고려해봅시다.
물론 새로운 플랫폼의 속도는 인상적이지만 실험적으로 확인하는 것이 좋습니다.
1. 테스트 조건
계산 속도는 여러 요인에 따라 달라집니다. 따라서 다른 테스트 조건에서 이 연구의 결과로 얻은 데이터는 다를 수 있습니다. 즉, 성능의 절대 값은 다르지만 상대 값은 유사해야 합니다 (인증 플랫폼의 경우).
MQL5의 iMA 함수는 계산 결과 자체를 반환하지 않기 때문에 (인디케이터의 핸들을 반환) 다음 두 함수의 속도를 테스트합니다: iMA 및 CopyBuffer.
- 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_SMA | MODE_EMA | MODE_SMMA | MODE_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. 다양한 이동 평균 알고리즘에 대한 성능 테스트 결과
이동 평균 계산의 여러 경우에 대해 계산 속도에서 상당한 차이를 볼 수 있습니다. 이게 무슨 뜻이죠? MQL5 개발자가 제공하는 이동 평균 계산의 여러 알고리즘은 계산 성능이 다릅니다. 빠른 알고리즘 (케이스 6)과 느린 방법 (케이스 3 및 4)이 있습니다. 따라서 이동 평균을 사용하는 MQL5에서 프로그램을 작성할 때 올바른 알고리즘을 선택하는 것이 필요합니다.
각 이동 평균 모델 (0-6)의 계산 시간은 다음 그림에 자세히 나와 있습니다 (표 2 참조).
그림 2. MODE_SMA 모드의 MA 계산 성능
그림 3. MODE_EMA 모드의 MA 계산 성능
그림 4. MODE_SMMA 모드의 MA 계산 성능
그림 5. MODE_LWMA 모드의 MA 계산 성능
MetaTrader 4와 MetaTrader 5의 두 플랫폼의 계산 성능을 비교하는 것은 흥미롭습니다. 결과는 표 2, 사례 №0 (MQL4) 및 사례 №2 (MQL5)에 나와 있습니다.
편의상 iMA 표준 인디케이터의 계산 결과를 별도의 차트와 표로 결합해보겠습니다 (그림 6 참조). 테스트 계산 시간은 Y 축에 표시됩니다.
그림 6. MetaTrader 4 и MetaTrader 5 계산 성능 비교 차트
결론:
- 새로운 MetaTrader 5 플랫폼은 이전 MetaTrader 4보다 40% 더 빠릅니다.
- SMA, EMA 및 SMMA 모델 (케이스 №6), LWMA (케이스 №2 및 №5)에서 가장 빠른 성능을 달성했습니다.
- 테스트 케이스의 경우 표준 인디케이터 iMA를 사용하면 다른 모델의 계산 성능이 거의 동일합니다. MovingAverages.mqh 라이브러리 함수에 대해서는 사실이 아닙니다. 모델에 따라 성능은 거의 주문 (0,00023 ~ 0,0045)만큼 다릅니다.
- 제시된 결과는 "콜드 스타트"에 해당하며 클라이언트 터미널의 글로벌 캐시에 미리 계산된 데이터가 없습니다.
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,00027 | 0,000117 (사례 6) |
MODE_LWMA | 0,0045 | 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[],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 | М1 | 21 |
6 | М1 | 34 |
7 | М1 | 55 |
8 | М1 | 89 |
9 | М1 | 233 |
10 | М1 | 377 |
11 | М1 | 610 |
12 | М1 | 987 |
표 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. 자동 테스트 자동 테스트 프로그램
결과: (X 축은 로그 시간 척도를 가짐)
그림 8. Timeframe 매개 변수 (Y) 및 이동 평균 계산 성능 (X)
그림 9. 기간 매개 변수 (Y) 및 이동 평균 계산 성능 (X)
추가 조사 결과의 결론:
- timeframe 매개 변수는 중요하지 않으며 계산 성능에 영향을 주지 않습니다 (그림 8 참조)
- 기간은 SMA, EMA 및 SMMA 모델의 이동 평균 계산 성능에 중요한 매개 변수가 아닙니다. 그러나 대조적으로 LWMA 모델에 대한 계산 속도가 크게 (0,00373 초에서 0,145 초로) 느려집니다 (그림 9 참조).
결론
이동 평균 알고리즘을 잘못 선택하면 프로그램의 계산 성능이 저하 될 수 있습니다.
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/106