最適化を最適化する・・・//MQL4の高速化(1) 速度測定

商用の指標トレードEA「AutoForex_EventExpress」は、こちらの記事によると、相場環境の変化に応じて着々とバージョンアップが図られているようです。(セカンドインパクト...名前だけで買ってしまいそう 笑) 一方、「DailyImpact」の方は、数量限定!リアル口座お試し版! を申し込み受付中とのこと。指標トレードは、デモとリアルでの違いが最も顕著に現れるタイプなので、リアルで試せるのは良いですね。
ちなみに、DailyImpactの開発者である Dr.ヘパ 氏のブログには、DLL関係の興味深い記事が掲載されています。DLL を作る人なら知っておいて損は無いと思うので、読んでみてください。





さて、本題に入ります。
平均的なEA利用者は、おそらく、MT4 の Optimization を頻繁におこなって、パラメータの最適化を行うことが多いと思います。俗にオプチと称して何時間も計算させているのを耳にすると、開発者としては、如何に高速なコードを書けるか?が重要なのかなと感じます。バックテストに5時間掛かるプログラムを2時間で終わらせるように出来たら、シアワセですよね。


…と言う訳で、今日は高速化のお話。
まともな開発環境であれば、プログラムを作って、一通り実行すると、何処の部分に何秒掛かっているのかを調べる(プロファイリングする)ツールがあって、何処を改善すれば、どのくらい高速化できるか?見積もって作業することができます。しかし、MQL4 には、そんな便利ツールは無いので、まず始めに、ある処理にどのくらい時間が掛かるかを調べてみたいと思います。

int start()
{
   int start = GetTickCount();
   for(int i= 0;i<10000000;i++){

      int x = MathRand();

   }
   Alert("Calculation time is   ",GetTickCount() - start, "   milliseconds.");
   return(0);
}

このスクリプトは、MathRand() を一千万回実行した時に掛かった時間(ミリ秒)を表示します。CPUによっては、もっとループ回数を増やさないと経過時間がゼロに近くなってしまうかもしれません。また、この測定値をそのまま MathRand に掛かった時間と考えるのは早計で、for ループを回すのに掛かった時間、int x の定義と、代入に掛かった時間も含まれます。そして、それ以前に、CPUの負荷状態によって値がかなりブレます。何度か測定して平均値を求めた方が良いかもしれません。




関数1個の実行時間を調べても、あまり高速化に関係無いのですが、、これを利用すると、同じ目的の2つの異なるプログラムの書き方のどちらが速いか?が判りやすくなります。
例えば、

for(int i= 0;i<10000000;i++){
      int x = Minute();
      int y = Minute();
}

↑x,y 共に Minute() の値を代入。

for(int i= 0;i<10000000;i++){
      int x = Minute();
      int y = x;
}

↑Minute()の呼び出し回数を減らしてみた。
上の2つは、どちらも x,y に同じ値が入るので同じ目的のプログラムなのですが、実行時間を比べてみると、

なんと2倍以上も差があります。ここにプログラムの高速化の余地があるわけです。(実際 Minute() の呼び出し回数を1個減らしたところでEAの高速化にはほとんど関係ないので、あくまでもサンプルということでご理解ください。ただ、一般的な傾向として、MQL4 の関数の呼び出しは時間が掛かるものが多いので、呼び出し回数の削減はやっておいて損は無いです。塵も積もれば山となりますから。。。)





どんなプログラムを書くと高速なのか?のノウハウは、ヘルプにはほとんど書かれていないのですが、唯一 StringConcatenate の項目だけは、

The StringConcatenate() works faster and more memory-saving than when strings are concatenated using addition operations (+).

と書かれています。文字列を「+」で繋ぐよりも、StringConcatenate の方が速いという意味だと思うのですけど・・・
実際どのくらい faster なのか?を以下のサンプルを使ってご自身で調べてみてください。

int start()
{
   string text;
   int start = GetTickCount();
   for(int i= 0;i<1000000;i++){
      text=StringConcatenate("Account free margin is ", AccountFreeMargin(), "Current time is ", TimeToStr(TimeCurrent()));
   }
   Alert("StringConcatenate time is   ",GetTickCount() - start, "   milliseconds.");
   start = GetTickCount();
   for(i= 0;i<1000000;i++){
      text="Account free margin is " + AccountFreeMargin() + "Current time is " + TimeToStr(TimeCurrent());
   }
   Alert("Plus operation time is   ",GetTickCount() - start, "   milliseconds.");

   return(0);
}

文字結合は時間が掛かるので、百万回に減らしています。



結果は敢えて書きませんが、えっ?と思うぐらいにアレだったりします。
何事も確認してみることが大事ということです。(続く)