FX
MQL4のiBarShiftでFX自動売買の時刻から足を探す方法

MQL4のiBarShiftは、指定した時刻に対応するローソク足の位置を調べる関数です。FX自動売買のログに残した日時から、そのときの足の価格や指標値を調べ直すときに役立ちます。返ってくるのは価格や経過本数ではなく、現在の時系列におけるshift番号です。
最初に押さえたいのは、見つからないときの扱いと、返された番号の読み戻しです。番号が得られただけで対象が正しいと判断せず、iTimeでその足の開始時刻を確認しましょう。この記事ではMQL4の仕様を基準に、引数、exact、履歴の欠け、発注しない確認例を順に説明します。
- 時刻から足の位置を探す方向と戻り値を理解できる
- exactによる未発見時の扱いを選び分けられる
- iTimeで検索した足の時刻を読み戻して照合できる
- 番号の変化と履歴不足を区別して原因を調べられる
MQL4のiBarShiftとFX自動売買の時刻

時刻からshiftへ変換する関数
時系列では、最新の足を0として、過去へ進むほど大きいshiftで参照します。しかし、保存したログが「ある日の10時15分」という時刻なら、その足が現在何本前にあるかはすぐには分かりません。そこでiBarShiftへ時刻を渡し、参照に使える番号を求めます。
変換の向きはiTimeと逆です。iTimeは銘柄、時間足、shiftから足の時刻を返し、iBarShiftは銘柄、時間足、時刻からshiftを返します。この二つを往復させると、検索対象と実際に選ばれた足の対応を確認できます。
関数の結果は整数です。例えば5が返れば、取得時点でshift5の足を表します。5秒前、5分前、検索対象から5本先という意味ではありません。どの時間足で5本前なのかは、関数に指定した時間足で決まります。
| 目的 | 関数 | 入力から出力への向き |
|---|---|---|
| 足の位置を調べる | iBarShift | 日時からshift |
| 足の開始時刻を調べる | iTime | shiftから日時 |
| その足の高値を読む | iHigh | shiftから高値 |
| その足の終値を読む | iClose | shiftから終値 |
例えば一週間前の判定を再確認するなら、記録した時刻をiBarShiftへ渡し、戻った番号をiTimeとiCloseへ渡します。そのときの銘柄や時間足まで同じにしないと、時刻だけ合っていても別のデータを読んでしまいます。番号の正しさだけでなく、何のデータから得た番号なのかを一緒に考えることが大切です。
MQL4の定義はMetaQuotesのiBarShiftリファレンスで確認できます。MQL5の記事も検索に出てきますが、同じ名前の関数であっても、説明を混ぜずに使用言語のリファレンスを基準にします。
四つの引数を明示して読む
書式はiBarShift(symbol, timeframe, time, exact)です。symbolは銘柄、timeframeは時間足、timeは検索するdatetime、exactは対応する足が見つからない場合の返し方を指定します。exactを省略するとfalseです。
symbolのNULLは現在のチャートの銘柄、timeframeの0は現在のチャートの時間足を意味します。小さな確認コードでは便利ですが、別のチャートへ移して使うと検索対象も変わります。固定の銘柄や時間足を確認したい場合は、値を明示するほうが検証条件を読み取りやすくなります。
timeへ渡すのはMQL4のdatetimeです。日本時間で記録した文字列を、変換せずサーバーのチャート時刻と同じものとして渡してはいけません。まずログの時刻がどの基準で記録されたかを確認し、チャートの足の開始時刻と同じ基準にそろえます。
銘柄名も口座に存在する正式名称を使います。末尾に記号が付く銘柄と付かない銘柄を取り違えると、期待した履歴を読めない場合があります。別口座の同じ通貨ペアを比較する際も、サーバーや配信履歴が同じとは限らないため、検索条件を一組として残します。
この段階では、時刻を探すだけの処理と売買処理をつながないようにします。まず入力した銘柄、時間足、検索時刻と戻り値をログへ出し、人が画面と照合できるようにします。正常な結果と未発見の結果の両方を確認したあとで、価格取得など次の処理へ渡す設計を考えましょう。
exactは未発見時の扱いを決める
MQL4公式では、iBarShiftは指定時刻を含む足の位置を返す関数と説明されています。その時刻に対応する足が履歴の欠けなどで存在しない場合、exactがtrueなら-1、falseなら近くの足の位置を返すという指定です。
ここで注意したいのは、falseで番号が返っても「その時刻の足が確実に存在した」とは言えないことです。近くの足への置き換えを許した結果かもしれません。過去のログと価格を厳密に照合したい用途では、見つからないことが分かる設計のほうが、別の足で処理を続けるより判断しやすい場合があります。

一方、チャート上でおおよその位置を示すだけなど、近い足でよい用途も考えられます。その場合も「どの程度離れていてもよいか」はEA側で決める条件です。falseを指定しただけで、その結果が目的に合った近さであると保証されるわけではありません。検索後の足の時刻を読み戻して判断します。
また、変数名のexactから、別言語の説明や想像だけで「開始時刻との完全一致を調べる関数」と置き換えないでください。足の開始時刻そのものとの一致が必要なら、検索した後にiTimeの戻り値と検索時刻を比較し、その条件を明示します。関数の検索仕様と、自分のプログラムが要求する一致条件は分けるのが確実です。
-1が返った場合は、その番号をそのまま配列や指標のshiftへ渡さず、その確認処理を見送ります。見送りは売買条件が不成立だったという意味でもありません。データが確認できなかった状態を別に扱うことで、未取得を売り・買いのどちらかへ誤って変換するのを防げます。
shiftを日時の代わりに保存しない
shiftは現在の足からの相対位置なので、新しい足が増えると同じ日時の足の番号は変わります。今日のshift10が、明日も同じ日時を指すわけではありません。後から追跡するために残す情報は、番号だけでなく銘柄、時間足、足の開始時刻です。

例えばログへshift5だけを残して、翌日その番号の終値を読むと、別の足を読んでしまいます。足の開始時刻を残しておけば、後からiBarShiftで現在の番号を調べ直せます。ただし、必要な履歴が取得できることが前提なので、時刻を残せば必ず再現できるという意味ではありません。
コードの一つの確認処理の中でも、複数の値を読む間に新しい足が始まる可能性があります。繰り返し処理や長い待機を挟むなら、同じshiftを使っているだけで同じ足だと判断せず、必要な箇所で足の時刻を再確認します。特に現在足を基準とする比較では、この境界がずれの原因になります。
複数時間足の売買ルール全体を設計する話は、EAのマルチタイムフレームで確定足をそろえる方法で扱っています。本記事では、すでにある一つの時刻から足を検索し、その結果が正しいか調べる部分に絞ります。
MQL4のiBarShiftを読み戻して検証

最初は既知の足で往復確認する
最初のテストでは、過去の足の開始時刻をiTimeで取得し、その時刻をiBarShiftへ渡します。自分で時差換算した文字列を使うより、同じ履歴から得た時刻を入力するほうが、関数の対応関係を確かめやすいからです。
以下は現在のチャートについて、五本前の足の開始時刻を取得し、検索後の足の時刻を読み戻すスクリプト例です。注文を送るコードは含めていません。実行途中に新しい足が始まる可能性もあるため、戻り値が必ず5かどうかより、読み戻した時刻が一致するかを確認します。
#property strict
void OnStart()
{
string symbol = Symbol();
int timeframe = Period();
int original_shift = 5;
if(iBars(symbol,timeframe) <= original_shift)
{
Print("Not enough history");
return;
}
ResetLastError();
datetime target = iTime(symbol,timeframe,original_shift);
int err_time = GetLastError();
if(target == 0 || err_time != 0)
{
Print("Time lookup failed: ",err_time);
return;
}
ResetLastError();
int found = iBarShift(symbol,timeframe,target,true);
int err_shift = GetLastError();
if(found < 0 || err_shift != 0)
{
Print("Bar lookup failed: ",found," err=",err_shift);
return;
}
ResetLastError();
datetime actual = iTime(symbol,timeframe,found);
int err_readback = GetLastError();
if(actual == 0 || err_readback != 0 || actual != target)
{
Print("Readback mismatch: err=",err_readback);
return;
}
Print(symbol," tf=",timeframe,
" target=",TimeToString(target,TIME_DATE|TIME_SECONDS),
" shift=",found,
" actual=",TimeToString(actual,TIME_DATE|TIME_SECONDS));
}
これは処理の考え方を示す説明用のコードで、利用者の環境での実行結果やコンパイル済みファイルの配布ではありません。MetaEditorで確認し、必要な履歴を表示したデモ環境で試してください。読み戻しの判定で見送った場合は、注文側へつなげず、どの情報が不足したかを調べます。
この例では検索時刻に足の開始時刻を使っているため、最後にactualとtargetの一致を確認しています。任意の足の途中の時刻を検索する用途では、この等値比較をそのまま流用しません。何をもって対応したと判断するのかを、その用途に合わせて決める必要があります。
読み戻しに使うMetaQuotesのiTimeリファレンスでは、ローカル履歴が読み込まれていない場合に0を返すことが説明されています。検索結果の番号だけでなく、次の関数で必要な情報が得られたかまで確認する理由です。
足の途中と履歴の欠けを分ける
既知の開始時刻で往復確認ができたら、次は対象足の途中の時刻を使う場合を調べます。例えば1分足の開始時刻から30秒後を試すなら、その時刻が実際に存在する足の時間範囲内かを確認します。返された足の開始時刻と検索時刻が同じでないことだけを、失敗と判定してはいけません。
これに対して、取引がない時間帯や履歴の欠けに当たる時刻は別のケースです。exactのtrueとfalseで戻り方が変わり得るため、どちらの結果もiTimeで読み戻します。近い足が返ったときに、それをそのまま指定時刻の実在データとして扱わないことが確認の目的です。

| 確認する入力 | 見る結果 | その後の扱い |
|---|---|---|
| 履歴にある足の開始時刻 | shiftと読み戻した開始時刻 | 同じ開始時刻か比較する |
| 実在する足の途中の時刻 | 対応する足の開始時刻 | 開始時刻の等値だけで失敗にしない |
| 履歴の欠けに当たる時刻 | exactごとの未発見・近い足 | 置き換えを許す用途か判断する |
| 履歴範囲外の古い時刻 | 戻り値と取得エラー | 必要な履歴があるか確認する |
| 新しい足が増えた後の同じ時刻 | 番号の変化と時刻の一致 | 番号が変わっても対象時刻で追う |
時間足の秒数を使って区間を考える場合でも、足の本数と実時間を単純に掛けて距離を推定しないようにします。取引のない時間帯やデータの欠けが挟まれば、経過時間と足の本数は対応しないためです。特に週末をまたぐ検索では、実際の足の開始時刻を確認するほうが説明しやすくなります。
テストで作った時刻がどのケースに該当するか不明なら、先にチャートと履歴を確認します。未発見の例を作るために適当な日時を入れ、必ず-1になると断定しないようにしてください。検証に使った入力と、実際に返った値の組を見て判断します。
異なる時間足の配列へ流用しない
iBarShiftで得た番号は、検索に使った銘柄と時間足の時系列に属します。H1を検索して得たshiftを、そのまま現在のM5チャートのHigh配列へ渡すと、別の時間足の足を読んでしまいます。整数が同じでも、それぞれの配列で指す対象は違います。
H1の高値を調べたいなら、検索したのと同じ銘柄・PERIOD_H1・取得したshiftをiHighへ渡します。現在チャートのHigh配列を使いたい場合は、最初からそのチャートの銘柄と時間足で求めた番号かを確かめます。引数の組を共通の変数として持つと、途中で0や別の定数を混ぜる間違いを減らせます。
検索後に価格を読むときも、戻り値とエラーを確認します。時刻検索の成功と価格取得の成功は、別の段階です。iTimeで対象が正しいと分かっても、その後の読取が失敗したら、価格を確認できたとは扱いません。
MetaQuotesのiHighの説明でも、銘柄・時間足・shiftの指定と、履歴がない場合の扱いを確認できます。指標の値へ進む場合も同様に、検索対象の組とその関数の引数をそろえます。
読み取りに使う配列の向きや添字の意味が曖昧なら、MQL4の配列と足の添字を確かめる方法を先に確認してください。番号が得られることより、その番号がどのデータに属するかを説明できることが大切です。
MQL4のiBarShiftは時刻で確かめる
iBarShiftの確認手順は、検索対象の銘柄と時間足を固定し、時刻を渡し、戻り値を確認してからiTimeで読み戻す流れです。未発見と売買条件の不成立を区別し、データが確認できない場合は後続の判定を見送る形にします。

結果がおかしいときは、最初に時刻の基準、次に銘柄と時間足、続いて履歴の範囲とexactを調べます。番号が以前と違うだけなら、新しい足が増えたことによる変化かもしれません。同じ開始時刻を追えているかを確認すると、正常な相対位置の変化と、本当の参照ずれを分けられます。
この関数は、FX自動売買の過去の判定を調べるための部品です。検索した足の終値があとから分かったとしても、その時点の売買判断で使えたとは限りません。検証対象の時刻に確定していた情報かどうかは別に確認し、後から得た値を当時の条件へ混ぜないようにしましょう。
まずは既知の足で往復確認を行い、足の途中、未発見、時間足違い、新しい足が始まる境界へと範囲を広げます。関数名を覚えるだけで終わらせず、どの入力から何が返り、どの条件なら次へ進めるのかを確認してからEAの処理に組み込んでください。
EA作成ツールの検証範囲を確認する
生成コードの動作テスト・コンパイル結果と、その限界 →記事内の戦略や個別のEAの収益性を検証した結果ではありません。学んだルールを、形にしてみよう。
EA作成ツールを開く ↗