バックテストの結果が実運用の成績と大きくズレて、

手法そのものを疑ってしまったことはないでしょうか。

原因の1つとして見落とされがちなのが、

ブローカーが提供するヒストリカルデータ自体に欠落や、

出来高が0のまま記録されたバーが混ざっているケースです。

この記事では、MQL4のiVolume関数で出来高を1本ずつ確認する方法と、

CopyRates関数で四本値・出来高をまとめて配列取得し、

欠落の疑いを自動検出するスクリプトの作り方を解説します。

この記事で分かること
・iVolumeで出来高を1本ずつ取得する方法
・CopyRatesで四本値をまとめて配列取得する方法
・ヒストリカルデータの欠落を自動検出する設計
・MQL4におけるCopyRatesの立ち位置
  1. なぜヒストリカルデータの欠落に気づく必要があるのか
    1. 欠落があるとバックテストの信頼性が落ちる
    2. ブローカーを乗り換えた直後に起こりやすい
    3. 目視では気づきにくい
  2. iVolumeで出来高を1本ずつ取得する
    1. iVolume関数の書式
    2. 出来高が0のバーは「データが無い」合図
    3. iVolumeだけでは1本ずつしか確認できない
  3. CopyRatesで四本値と出来高をまとめて取得する
    1. CopyRatesの書式
    2. MqlRates構造体のメンバー
    3. CopyRatesはMQL4で後から追加された関数である
  4. 既刊copyrates-mql5.mdとの違い
    1. MQL5はCopyRatesが標準の取得方法
    2. MQL4はCopyRatesが「追加の選択肢」
    3. 本記事ならではの着眼点
  5. 欠落バーを検出する設計
    1. 出来高0のバーを数える
    2. 時刻の間隔が不自然に開いていないか調べる
    3. PeriodSecondsで時間足を秒数に変換する
  6. 実際に動くコード全体
  7. MetaEditorでの実行手順
  8. よくあるエラーと注意点
    1. CopyRatesが-1を返す
    2. ECN系ブローカーでtick_volumeの意味が違う
    3. MQL5との違い
  9. よくある質問
    1. 欠落が見つかったらどう対処すればいいですか?
    2. CheckBarsの本数はどれくらいにすればいいですか?
    3. このチェックだけでバックテストの信頼性は保証されますか?
  10. 【MQL4】iVolumeとCopyRatesで過去の出来高・四本値をまとめて取得し、ヒストリカルデータの欠落を確認する方法について解説してみた:まとめ
    1. 関連記事

なぜヒストリカルデータの欠落に気づく必要があるのか

まず、この確認がなぜ必要なのかを確認します。

欠落があるとバックテストの信頼性が落ちる

本来存在するはずのバーが抜けていたり、出来高0のまま記録されていたりすると、

ストラテジーテスターの計算がそのバーで不自然になり、結果全体の信頼性が下がります。

ブローカーを乗り換えた直後に起こりやすい

ヒストリーセンターにまだ全期間のデータがダウンロードされていない状態で、

古い日付のチャートを開くと、一部の期間だけデータが粗くなっていることがあります。

目視では気づきにくい

出来高0のバーやわずかな時刻のズレは、チャートを目で見ているだけでは気づきにくく、

スクリプトで機械的に検出する必要があります。

iVolumeで出来高を1本ずつ取得する

まずは最も基本的なiVolume関数の使い方を確認します。

iVolume関数の書式

long iVolume(
   string symbol,      //通貨ペア(NULLで現在のチャートの通貨ペア)
   int    timeframe,   //時間足(0で現在のチャートの時間足)
   int    shift        //バーのシフト(0が現在のバー)
   );

戻り値の型はlongで、

そのバーのティックボリューム(約定を伴う価格変化の回数)を返します。

出来高が0のバーは「データが無い」合図

用語補足
・ティックボリュームは実際の取引量ではない
・価格が何回動いたかの回数が記録される
・0は値動きが1度も記録されていないことを示す

iVolumeだけでは1本ずつしか確認できない

iVolumeはshiftを指定して1本ずつ呼ぶ関数のため、

まとまった本数を確認したい場合はループで回す必要があり、

配列として一括取得する方法も合わせて知っておくと効率的です。

CopyRatesで四本値と出来高をまとめて取得する

CopyRates関数の仕様を確認します。

CopyRatesの書式

int CopyRates(
   string   symbol_name,  //通貨ペア
   int      timeframe,    //時間足
   int      start_pos,    //開始位置(シフト)
   int      count,        //取得する本数
   MqlRates rates_array[] //取得結果を格納する配列
   );

戻り値はコピーされた本数で、失敗した場合は-1を返します。

MqlRates構造体のメンバー

メンバー 型 内容
time datetime バーの開始時刻
open/high/low/close double 四本値
tick_volume long ティックボリューム
real_volume long 実出来高(多くのFXブローカーでは0)
spread int スプレッド

CopyRatesはMQL4で後から追加された関数である

MQL4は元々、

iOpen/iClose/iHigh/iLow/iVolumeという、

「1本ずつ取得する」関数群が主流でした。

CopyRatesはMQL5との構文統一のために後から追加された、

配列一括取得用の関数です。

既刊copyrates-mql5.mdとの違い

MQL5版の記事と何が違うのかを明確にします。

MQL5はCopyRatesが標準の取得方法

既刊記事で解説した通り、MQL5にはiOpen/iClose相当の単純な関数が無く、

CopyRates系が標準の取得方法として設計されています。

MQL4はCopyRatesが「追加の選択肢」

MQL4では今でもiOpen等が使えるため、

CopyRatesは「複数本をまとめて処理したいときに使う、

追加の選択肢」という位置づけになります。

本記事ならではの着眼点

本記事は関数の使い方そのものではなく、

CopyRatesで取得した配列を使ってヒストリカルデータの品質を検査するという、

一歩進んだ活用方法に焦点を当てています。

欠落バーを検出する設計

実際に検出ロジックを組み立てます。

出来高0のバーを数える

if(rates[i].tick_volume == 0)
   zeroVolumeCount++;

配列の各要素のtick_volumeが0であれば、カウンターを増やすだけの単純な判定です。

時刻の間隔が不自然に開いていないか調べる

long diff = rates[i].time - rates[i + 1].time;
if(diff > periodSeconds * 2)
   gapCount++;

隣接するバーの時刻差が、その時間足本来の間隔の2倍を超えていたら、

欠落の疑いがあると判定します。

PeriodSecondsで時間足を秒数に変換する

PeriodSeconds()は指定した時間足を、

秒数(例: PERIOD_H1なら3600)に変換する関数で、

時間足ごとに期待される間隔を計算する際に使います。

実際に動くコード全体

ここまでの要素をまとめた、実際に動くスクリプトです。

//+------------------------------------------------------------------+
//|                                   HistoricalDataGapCheck.mq4      |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link      "https://creator.fx-ea-system-project.com/"
#property version   "1.00"
#property strict
#property script_show_inputs

input int CheckBars = 200;   //確認する本数

void OnStart()
  {
   MqlRates rates[];
   ArraySetAsSeries(rates, true);

   int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, CheckBars, rates);

   if(copied <= 0)
     {
      Print("CopyRatesに失敗しました。エラーコード=", GetLastError());
      return;
     }

   int zeroVolumeCount = 0;
   int gapCount = 0;
   int periodSeconds = PeriodSeconds(PERIOD_CURRENT);

   for(int i = 0; i < copied - 1; i++)
     {
      if(rates[i].tick_volume == 0)
         zeroVolumeCount++;

      long diff = rates[i].time - rates[i + 1].time;

      if(diff > periodSeconds * 2)
        {
         gapCount++;
         Print("欠落の疑い: ", TimeToString(rates[i + 1].time),
               " と ", TimeToString(rates[i].time), " の間");
        }
     }

   Print("取得本数=", copied,
         " 出来高0の本数=", zeroVolumeCount,
         " 欠落の疑いの箇所=", gapCount);

   //iVolumeで直近5本だけを個別にも確認しておく
   for(int s = 0; s < 5 && s < copied; s++)
     {
      Print("iVolume shift=", s, " volume=", iVolume(_Symbol, PERIOD_CURRENT, s));
     }
  }

MetaEditorでの実行手順

実際にMT4で動かすまでの手順を確認します。

  1. MetaEditorで新規スクリプト「HistoricalDataGapCheck」を作成し、上のコードを貼り付けてコンパイルする
  2. エラー・警告が0件であることを確認する
  3. 確認したい通貨ペア・時間足のチャートにスクリプトをドラッグして実行する
  4. 「エキスパート」タブで、取得本数・出来高0の本数・欠落の疑いの箇所数を確認する
  5. 欠落が多い場合は、ヒストリーセンターからデータを再ダウンロードして再確認する

よくあるエラーと注意点

実装でつまずきやすいポイントをまとめます。

CopyRatesが-1を返す

注意
・通貨ペアや時間足の履歴が未取得の可能性がある
・一度チャートを開いてデータを読み込ませる
・GetLastError()で詳細なコードも確認する

ECN系ブローカーでtick_volumeの意味が違う

一部のブローカーでは出来高の記録方式が異なり、

0ではないものの実態を反映していないことがあるため、

0件かどうかだけで品質を断定せず、傾向として参考にする姿勢が安全です。

MQL5との違い

このコードのCopyRatesはMQL5と同じ書式です。

MQL5ではiVolumeの代わりに、

CopyTickVolumeという専用関数も用意されている点が、

MQL4との違いです。

よくある質問

ヒストリカルデータの確認について、よくある疑問に回答します。

欠落が見つかったらどう対処すればいいですか?

MT4の「ツール」→「ヒストリーセンター」から、

該当する通貨ペア・時間足のデータを一度削除し、

インターネット接続を確認した上で再ダウンロードすると改善することが多いです。

改善しない場合は、別のVPSやブローカーのサーバーから再取得することも検討してください。

CheckBarsの本数はどれくらいにすればいいですか?

バックテストで使う期間と同じ本数を確認するのが基本です。

数年分のバックテストを行う場合は、一度に大きな本数を指定せず、

期間を分けて複数回実行すると処理が軽くなります。

このチェックだけでバックテストの信頼性は保証されますか?

保証はできません。

本記事のチェックはヒストリカルデータの「明らかな欠落」を見つける一次確認に過ぎず、

スプレッドの再現性やスリッページなど、バックテストと実運用のズレには他の要因も関わります。

【MQL4】iVolumeとCopyRatesで過去の出来高・四本値をまとめて取得し、ヒストリカルデータの欠落を確認する方法について解説してみた:まとめ

バックテストと実運用の結果がズレる原因の1つに、ヒストリカルデータ自体の欠落があります。

iVolumeで出来高を1本ずつ確認する方法と、

CopyRatesで四本値・出来高をまとめて配列取得する方法を、

組み合わせることで、

出来高0のバーや時刻の不自然な間隔を機械的に検出できます。

CopyRatesはMQL4では後から追加された「追加の選択肢」

であり、既存のiOpen系関数と役割を分けて覚えておくと理解しやすくなります。

関連記事