English Русский 中文 Español Deutsch Português 한국어 Français Italiano Türkçe
MQL5における移動平均計算パフォーマンス検証

MQL5における移動平均計算パフォーマンス検証

MetaTrader 5 | 6 10月 2015, 13:00
2 935 0
Sergey Pavlov
Sergey Pavlov

はじめに

「移動平均」の使用はマーケットの時系列分析、インディケータやExpert Advisorsプログラミングではよくある実践方法です。それは最もよく使用される価格データ平滑化手法です。MQL言語の新バージョンでは、多くの「移動平均」アルゴリズムが使用可能です。

それらの間の違いは何でしょうか?ほんとうに「移動平均」の特定のアルゴリズムに応じて計算スピードは変わりますか?どのアルゴリズムが速いのでしょうか?

「移動平均」の計算スピードはMetaTrader 4に比べるとMetaTrader 5 では速くなりましたか?そんな質問がたくさん浮かびます。では、それについて考察していきましょう。

もちろん、新しいプラットフォームのスピードはすばらしいものですが、実験的に確認するのが良いでしょう。


1. 条件検証

計算スピードは多くの要因に左右されます。そのため、この調査の結果得られるデータは他の検証条件で得られるデータとは異なるかもしれません。言い換えれば、パフォーマンスの絶対値は違いますが、相対値は類似しているはずだということです。(ある特定のプラットフォームにつぃて)

MQL5のiMA関数それ自体は計算結果を返さない(インディケータのハンドルを返します。)という事実のために、2つの関数スピードを検証します。 対象となるのはiMA関数と CopyBuffer関数です。

検証条件
  • CPU: Core i7 965
  • シンボル: "EURUSD"
  • 価格データサイズ:10000 エレメント
  • クライアント端末:自立型、チャート内バーの最大値は10,000に設定されています。
  • 移動平均モデル:MODE_SMA, MODE_EMA, MODE_SMMA, MODE_LWMA
  • 計算スピードの正確性は2つの有効桁に限定されます。
  • 「移動平均」関数を呼べる回数: 7


2. 検証方法

移動平均計算の時間を計測するには、ミリ秒で処理する GetTickCount()関数があります。 この精度は十分ではないので、計測の質を向上するためいくつかのサイクルを作成する必要があります。

ただし同じ計算と同じ入力データでループを複数回繰り返せば、結果はゆがんでしまいます。この理由は以下です。iMA関数はクライアント端末のグローバルキャッシュに対応するテクニカルインディケータのコピーを作成するからです。インディケータ(同じパラメータで)のコピーがすでにグローバルキャッシュにあれば、新規コピーは作成されず、インディケータのコピーの参照カウンターは増加します。

別の言い方をすれば、全バッファのインディケータは最初の呼び出し時一度だけ計算され、その後の呼び出し時には準備された値を取得するだけです。再計算するのは新規データのみです。

そのため、ループはインディケータの入力パラメータがサイクル中ユニークであるときに作成される必要があります。ここに選択された3つのそのようなパラメータがあります。すなわち、平均化期間、時間枠、適用価格です。

パラメータ 値範囲
平均化期間 1~100
時間枠 М1, М5, М15, М30
適用価格 PRICE_CLOSE, PRICE_OPEN, PRICE_HIGH, PRICE_LOW, PRICE_MEDIAN, PRICE_TYPICAL, PRICE_WEIGHTED

 

表1 入力パラメータの範囲

7とおりの異なる呼び出し手法を使って10,000エレメントの配列について移動平均値を計算します。(図4参照)


3. 調査結果

全結果は表1にまとめています。計算処理は秒単位の計算時間を用いて見積もられています。(表1参照)プログラムは移動平均の100х4х7=2800 タイプを計算し、われわれは10,000エレメントの価格配列について計算時間を判断します。シングルパス(サイクル)の計算時間はおおよそ合計時間を2800で割ったものと等しくなります。たとえば、1でSMAモードの場合、~0,0028/2800に等しくなります。

モード MODE_SMA MODE_EMA MODE_SMMA MODE_LWMA Platform
0 (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項にて)「移動平均」の計算処理について全体像をestimateします。

利便性のため、結果はグラフに表示します。(図1~5参照)「移動平均」の呼び出しタイプは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つのプラットフォームで計算処理を比較するのは興味深いことです。結果は表2にケースNo.0(MQL4)、ケースNo.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モデル(ケースNo.6)、LWMA(ケースNo.2、ケースNo.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. ケースNo.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. ケースNo.1

このケースでは、MovingAverages.mqhライブラリ関数を用いて4つのモデルの処理計算を行いました。すなわち、No.(SMA)、,No.2(EMA)、 No.3(SMMA)、 No.4(LWMA) です。

計算はすべてのデータ配列に対して行われます。

モデル 結果 最高結果
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. ケースNo.2

このケースではiMAの標準テクニカルインディケータとテストNo.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. ケースNo.3

ケースNo.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. ケースNo.4

ケースNo.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. ケースNo.5

テストNo.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. ケースNo.6

このケースでは、MovingAverages.mqhライブラリ関数(MQL4のiMAOnArrayのようなバッファ関数)を用いて4つのモデルの処理計算を行いました。すなわち、No.9(SMA)、,No.10(EMA)、 No.11(SMMA)、 No.12(LWMA) です。

計算はすべてのデータ配列に対して行われます。

モデル 結果 最高結果
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);
//---

配列インデックスは計算の前後で異なることに注意が必要です。

重要事項AsSeriesフラグは計算中falseに設定され、結果印刷時trueに設定されます。


6. その他の調査

計算能力の初期パラメータ効果についての質問に答えるために、いくつか追加計測を行います。

ご記憶だろうと思いますが、ケースNo.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 自動検証のためのautotestプログラム

図7 自動検証のためのautotest プログラム

結果: (X軸l対数時間尺度です)

図8 時間枠パラメータ (Y) と「移動平均」計算能力 (X)

図8 時間枠パラメータ (Y) と「移動平均」計算能力 (X)

図9 期間パラメータ (Y) と「移動平均」計算能力 (X)

図9 期間パラメータ (Y) と「移動平均」計算能力 (X)

追加調査の結果から導かれる結論:

  1. 時間枠パラメータは重要ではありません。それは計算能力に影響を与えません。(図8参照)
  2. 期間はモデルSMA、EMA、SMMAについての移動平均計算能力に重要なパラメータではありません。が、それはLWMAモデルについては計算速度を著しく下げます。(0.00373行から0.145へ)(図9参照)


おわりに

移動平均アルゴリズムの誤った選択はプログラムの計算能力を低下させます。

MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/106

添付されたファイル |
autotest__1.zip (10.86 KB)
インディケータの経済的計算原理 インディケータの経済的計算原理
自動化されたトレーディングシステムのプログラムコードではユーザーとテクニカルインディケータの呼び出しはほとんどスペースを取りません。たいてい数行のコード行ですむ簡単なものです。ただこの数行のコードがExpert Advisorの検証に必要な時間の多くを費やす、ということはよくあることです。インディケータ内でデータ計算に関連することはすべて、一見したよりもずっと綿密に配慮される必要があります。本稿ではこの件に関して詳しく述べていきます。
かずかずのインスツルメントで取引を行うExpert Advisorの作成 かずかずのインスツルメントで取引を行うExpert Advisorの作成
ファイナンシャルマーケットにおける資産の多様性概念はかなり古いもので常に初心者のトレーダーを魅了してきました。本稿では、複数通貨対応Expert Advisorの構築をトレード戦略を扱う最初の導入として最大限にシンプルな手法で行います。
単一インスツルメント上で異なるExpert Advisorsを使ったトレーディングのためのORDER_MAGICの使用 単一インスツルメント上で異なるExpert Advisorsを使ったトレーディングのためのORDER_MAGICの使用
本稿は、異なるExpert Advisorsの自動トレーディングの分割、組立て、同期同様magic-identificationを使用したインフォメーションコーディングの疑問について考察します。本稿は、より経験を積んだトレーダー同様初心者にも興味深い内容となっています。その理由は、Expert Advisorsおよび様々な戦略の複雑なシステムの同期を実装するのに有用な垂直ポジションの疑問に取り組んでいるからです。
ろうそく足パターンの分析 ろうそく足パターンの分析
日本式のろうそく足チャートの構築とろうそく足パターンの分析は技術分析のすばらしい領域となっています。ろうそく足の利点はデータ内部の動きを追跡できるデータ表現になっていることです。本稿では、ろうそく足タイプとパターン分類を分析し、 またろうそく足パターンを決定するインディケータについてお伝えしていきます。