【検証#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は以下を行わなければなりません。
- EURUSDのヒストリカルデータをメモリにロード
- 要求された時刻に対応するバーを検索(同期)
- 値を返す
これを毎ティック、20通貨ペア分繰り返すとどうなるでしょうか。
バックテストの負荷¶
ストラテジーテスターは、メインの通貨ペアのTick生成に合わせて、参照されている全通貨ペアのデータも同期させながら進めます。 これが猛烈なオーバーヘッドになります。
MQL5での検証コード¶
実際に20通貨ペアにアクセスするEAと、しないEAの負荷を比較できるコードを用意しました。
ファイル名: 15_MultiSymbol_Load.mq5
保存先: MQL5\Experts
パラメータ: AccessAllSymbols (true=20ペア / false=1ペア)
//+------------------------------------------------------------------+
//| 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¶
正確に同期するには、時刻を指定してバーの位置(シフト)を探す必要があります。
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 |
| データロード | 初回アクセス時は準備待ちが発生する(エラー処理必須) |
| データ同期 | 必ず iBarShift や CopyRates で時刻ベースで合わせる |
重厚長大なマルチカレンシーEAを作る前に、まずは軽量なシングルEAでロジックを磨くことをお勧めします。
ソースコードのダウンロード¶
この記事で紹介したコードをダウンロードできます。
ファイルの種類:EA(Expert Advisor)
保存先: MQL5/Experts/ フォルダ
使い方: MT5のナビゲーターから「エキスパートアドバイザ」を展開し、チャートにドラッグ&ドロップで適用
15_MultiSymbol_Load.mq5 をダウンロード