コンテンツにスキップ

【検証#12】その時刻判定、遅くない?文字列操作の罠

ベンチマーク実行結果

図:ベンチマーク実行結果

この記事の3行まとめ

  • 🐢 TimeToStr() で時刻判定するとバックテストが激重になる
  • 🐇 整数計算(TimeCurrent() % 86400)なら10倍以上高速
  • OnTick 内で文字列操作(String関数)は極力避けるべし

はじめに

この記事は、「とあるMetaTraderの備忘秘録」様のブログ記事を検証・紹介するシリーズの第12弾です。

EAのバックテスト(最適化)において、もっともボトルネックになりやすいのが OnTick 内の処理です。特に「特定の時間だけトレードする」というロジックでやりがちなミスがあります。

元ネタ

最適化を最適化する・・・MQL4の高速化(4)
https://fai-fx.hatenadiary.org/entry/20100705/1278263593
(2010年7月5日 公開)


遅いコード vs 速いコード

例えば「毎日 12:00 にトレードする」というロジックを考えます。

❌ 遅い実装(文字列変換)

MQL
// 現在時刻を文字列に変換:"2026.01.27 12:00"
string timeStr = TimeToString(TimeCurrent(), TIME_MINUTES);

// 文字列比較
if(StringSubstr(timeStr, 11, 5) == "12:00")
{
    // ...
}

人間には直感的で分かりやすいですが、コンピュータにとっては重労働です。 1. メモリ確保(文字列用) 2. 日時のフォーマット変換 3. 文字列の部分抽出 4. 文字列比較 5. メモリ解放

これを1回のティックごとに毎回行います。バックテストでは数百万回呼ばれるため、大きなロスになります。

✅ 速い実装(整数計算)

MQL
// 1日は 86400秒
// 12:00 は 0時から 12*3600 = 43200秒後

long seconds = TimeCurrent() % 86400; // 今日の経過秒数

if(seconds == 43200)
{
    // ...
}

これなら単純な割り算と整数の比較だけです。メモリ確保も発生しません。


MQL5での検証コード

実際にどれくらい速度差があるのか、1000万回ループで比較してみました。

ファイル名: 12_SpeedTest_Time.mq5
保存先: MQL5\Scripts

MQL
//+------------------------------------------------------------------+
//|                                       12_SpeedTest_Time.mq5       |
//| MQL検証シリーズ #12 検証用スクリプト                               |
//+------------------------------------------------------------------+
#property script_show_inputs
input int LoopCount = 10000000;

void OnStart()
{
   Print("=== 時刻判定 高速化ベンチマーク ===");
   datetime now = TimeCurrent();
   ulong start, timeStr, timeInt;

   // A: 文字列変換
   start = GetMicrosecondCount();
   int countA = 0;
   for(int i=0; i<LoopCount; i++)
   {
      datetime t = now + (datetime)i; // 毎回異なる時刻
      string s = TimeToString(t, TIME_MINUTES);
      if(StringSubstr(s, 11, 5) == "12:00") countA++;
   }
   timeStr = GetMicrosecondCount() - start;
   PrintFormat("A (String): %.3f ms", timeStr/1000.0);

   // B: 整数計算
   start = GetMicrosecondCount();
   int countB = 0;
   long target = 12 * 3600;
   for(int i=0; i<LoopCount; i++)
   {
      long t = (long)now + i;
      long seconds = t % 86400;
      if(seconds == target) countB++;
   }
   timeInt = GetMicrosecondCount() - start;
   PrintFormat("B (Integer): %.3f ms", timeInt/1000.0);

   // 結果
   if(timeInt > 0)
      PrintFormat("高速化倍率: %.1f倍", (double)timeStr / timeInt);
}

実行結果の目安

手元の環境での実行結果です:

Text Only
A (String):  4391.024 ms
B (Integer):   21.236 ms
高速化倍率:   206.8倍

なんと 200倍以上の差 が出ました。 文字列操作がいかに重いかがわかります。最適化のためにループ変数を使ってもこの差です。


実践テクニック

時間範囲(9時から15時まで)の判定

MQL
long now = TimeCurrent() % 86400;
long start = 9 * 3600;  // 09:00
long end   = 15 * 3600; // 15:00

if(now >= start && now < end)
{
    // トレード時間内
}

分単位の判定(毎時30分など)

MQL
// 1時間は3600秒
long minutes = (TimeCurrent() % 3600) / 60; 

if(minutes == 30)
{
    // 毎時30分
}

まとめ

ポイント 内容
TimeToStr デバッグログなど、人間が見る時だけ使う
ロジック判定 必ず整数計算(割り算・余り)を使う
効果 バックテスト時間が大幅に短縮される

「動けばいい」段階から「最適化を回す」段階になったら、ぜひこの高速化テクニックを取り入れてください。


ソースコードのダウンロード

この記事で紹介したコードをダウンロードできます。

ファイルの種類:スクリプト

保存先: MQL5/Scripts/ フォルダ
使い方: MT5のナビゲーターから「スクリプト」を展開し、チャートにドラッグ&ドロップで実行

12_SpeedTest_Time.mq5 をダウンロード


関連記事・用語