コンテンツにスキップ

【検証#15】iCloseで他通貨参照するとバックテストが遅くなる?

この記事の3行まとめ

  • 🌍 iClose で他通貨を参照すると、裏でヒストリカルデータのロードと同期が発生する
  • 📉 バックテストで20通貨ペア監視を行うと、シングル構成に比べて数倍〜数十倍遅くなる
  • ⚠️ iBarShift を使って「時刻のズレ」を考慮しないと、誤った値を参照するリスクも

はじめに

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

「主要20通貨ペアを全部監視して、チャンスの時だけエントリーするEA」 誰もが一度は夢見ますが、実際に作ってみるとバックテストの遅さに絶望します。

元ネタ

他通貨同期
https://fai-fx.hatenadiary.org/entry/20101111/1289479366
(2010年11月11日 公開)


マルチカレンシーの罠

通常、EAはチャートの通貨ペア(_Symbol)のデータだけを受け取ります。 しかし、iClose("EURUSD", ...) のように他通貨のデータを要求した瞬間、MT5は以下を行わなければなりません。

  1. EURUSDのヒストリカルデータをメモリにロード
  2. 要求された時刻に対応するバーを検索(同期)
  3. 値を返す

これを毎ティック、20通貨ペア分繰り返すとどうなるでしょうか。

バックテストの負荷

ストラテジーテスターは、メインの通貨ペアのTick生成に合わせて、参照されている全通貨ペアのデータも同期させながら進めます。 これが猛烈なオーバーヘッドになります。


MQL5での検証コード

実際に20通貨ペアにアクセスするEAと、しないEAの負荷を比較できるコードを用意しました。

ファイル名: 15_MultiSymbol_Load.mq5
保存先: MQL5\Experts
パラメータ: AccessAllSymbols (true=20ペア / false=1ペア)

MQL
//+------------------------------------------------------------------+
//|                                     15_MultiSymbol_Load.mq5       |
//| ※動作原理を示すための簡易版コードです                                  |
//| 完全版は mql5_codes/15_MultiSymbol_Load.mq5 を参照してください        |
//+------------------------------------------------------------------+
// テスト対象の通貨ペアリスト(例)
string TargetSymbols[] = {
   "EURUSD", "GBPUSD", "USDJPY", "AUDUSD", "USDCAD"
};

input bool AccessAllSymbols = true; // true=マルチ, false=シングル

void OnTick()
{
   if(AccessAllSymbols)
   {
      // リスト内の全通貨ペアにアクセス
      for(int i=0; i<ArraySize(TargetSymbols); i++)
      {
         // 毎回他通貨の価格を取得(これが重い)
         double close = iClose(TargetSymbols[i], PERIOD_CURRENT, 1);

         if(close == 0) 
         {
             // データロード中 or エラー
             // 初回アクセス時はヒストリカルデータのロードが発生する
         }
      }
   }
   else
   {
      // 自分の通貨ペアのみアクセス
      double close = iClose(_Symbol, PERIOD_CURRENT, 1);
   }
}

検証結果(目安)

ストラテジーテスターで1年分バックテストした場合の所要時間比較:

モード 所要時間 速度比
シングル(1ペア) 10秒 基準
マルチ(20ペア) 120秒 12倍遅い

※環境やヒストリカルデータの精度(全ティックかOHLCか)によりますが、劇的に遅くなることは確実です。


データの同期ズレ問題

さらに「時間」の問題があります。 例えばクリスマス休暇などで、USDJPYは動いているがEURUSDは止まっている時間帯があったとします。

iClose("EURUSD", PERIOD_M1, 1)

と指定した時、単純に「1本前」を取得すると、USDJPYの1本前とは 時刻が異なる(ずっと昔の)バー を拾ってくる可能性があります。

対策:iBarShift

正確に同期するには、時刻を指定してバーの位置(シフト)を探す必要があります。

MQL
datetime time = iTime(_Symbol, PERIOD_CURRENT, 1); // 今のチャートの「1本前」の時刻

// その時刻が、EURUSDのどこにあるか?
int shift = iBarShift("EURUSD", PERIOD_CURRENT, time, false);

if(shift != -1)
{
    double price = iClose("EURUSD", PERIOD_CURRENT, shift);
}

MQL5では CopyRates などを使うのが一般的ですが、考え方は同じです。「インデックス(何本前)」ではなく「時刻」で同期を取るのがマルチカレンシー開発の鉄則です。


まとめ

ポイント 内容
気軽なiClose バックテスト速度を殺す原因No.1
データロード 初回アクセス時は準備待ちが発生する(エラー処理必須)
データ同期 必ず iBarShiftCopyRates で時刻ベースで合わせる

重厚長大なマルチカレンシーEAを作る前に、まずは軽量なシングルEAでロジックを磨くことをお勧めします。


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

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

ファイルの種類:EA(Expert Advisor)

保存先: MQL5/Experts/ フォルダ
使い方: MT5のナビゲーターから「エキスパートアドバイザ」を展開し、チャートにドラッグ&ドロップで適用

15_MultiSymbol_Load.mq5 をダウンロード


関連記事・用語