EA(自動売買プログラム)やカスタムインジケーターを作るとき、「過去のローソク足の価格を取得したい」という場面は非常に多く出てきます。たとえば「1本前の足が陽線だったら買い」「直近5本の高値の中で最も高い価格を調べたい」など、ローソク足データの取得はMQL4プログラミングの基本中の基本です。
この記事では、MQL4でローソク足の始値・終値・高値・安値・開始時刻を取得するための5つの関数――iOpen()、iClose()、iHigh()、iLow()、iTime()の使い方を、サンプルコード付きでわかりやすく解説します。
5つの時系列アクセス関数の概要
MQL4には、ローソク足(バー)の価格情報を取得するための時系列アクセス関数が用意されています。iOpen関数は指定した通貨ペア・時間軸・バーシフトに対応するバーの始値を、iClose関数は終値を、iHigh関数は高値を、iLow関数は安値を返す関数です。それぞれの役割は以下のとおりです。
| 関数名 | 取得できる値 | 戻り値の型 |
|---|---|---|
iOpen() |
指定バーの始値(Open) | double |
iClose() |
指定バーの終値(Close) | double |
iHigh() |
指定バーの高値(High) | double |
iLow() |
指定バーの安値(Low) | double |
iTime() |
指定バーの形成開始時刻 | datetime |
5つの関数はすべて同じ引数の構成を持っており、一度覚えればすべてすぐに使いこなせます。
関数の書式と引数の意味
ここではiClose()を例に解説しますが、他の4つの関数もまったく同じ形式です。
double iClose(
string symbol, // 通貨ペア名
int timeframe, // 時間軸
int shift // バーの位置(シフト)
);
① symbol(通貨ペア名)
通貨ペア名は「気配値表示ウィンドウ」に表示されているとおりに記述します。特定の通貨ペア名を指定せず、EA等を適用したチャートの通貨ペアの終値を取得したい場合は、「NULL」と記述します。
NULLまたはSymbol()→ EAやインジケーターを適用中のチャートの通貨ペア"USDJPY"→ ドル円を明示的に指定"EURUSD"→ ユーロドルを明示的に指定
通貨ペアを直接記述するとどの通貨ペアチャートにセットしてもその通貨ペアを強制的にトレードしてしまうため、Symbol()と記述しましょう。
② timeframe(時間軸)
どの時間足のデータを取得するかを指定します。0またはPERIOD定数を使います。
| 定数 | 値 | 時間足 |
|---|---|---|
PERIOD_CURRENT |
0 | 現在のチャートの時間足 |
PERIOD_M1 |
1 | 1分足 |
PERIOD_M5 |
5 | 5分足 |
PERIOD_M15 |
15 | 15分足 |
PERIOD_M30 |
30 | 30分足 |
PERIOD_H1 |
60 | 1時間足 |
PERIOD_H4 |
240 | 4時間足 |
PERIOD_D1 |
1440 | 日足 |
PERIOD_W1 |
10080 | 週足 |
PERIOD_MN1 |
43200 | 月足 |
0を指定すると、EAやインジケーターを適用しているチャートの時間足が自動的に使われます。マルチタイムフレーム分析(MTF)を行いたい場合は、ここに上位足の定数を明示的に指定します。
③ shift(バーの位置)
終値を取得したいバーが現在のバーであれば「0」、1本前のバーであれば「1」、2本前のバーであれば「2」……と記述します。
0→ 現在(最新)のバー1→ 1本前のバー2→ 2本前のバーn→ n本前のバー
同じ記述でも時間が進むにつれて値が変化します。数字が大きくなるほど過去のバーを参照します。なお、shift=0の最新バーはまだ形成中なので、確定した値を使いたい場合はshift=1以降を使うのが一般的です。
基本的な使い方 ― 各関数のサンプルコード
まずは5つの関数それぞれを使って、ログにローソク足情報を出力する基本例を見てみましょう。
//+------------------------------------------------------------------+
//| 各時系列アクセス関数の基本的な使い方 |
//+------------------------------------------------------------------+
#property strict
void OnInit()
{
// 1本前(確定済み)のバーの各値を取得
double openPrice = iOpen(NULL, 0, 1);
double closePrice = iClose(NULL, 0, 1);
double highPrice = iHigh(NULL, 0, 1);
double lowPrice = iLow(NULL, 0, 1);
datetime barTime = iTime(NULL, 0, 1);
Print("=== 1本前のローソク足情報 ===");
Print("開始時刻: ", TimeToString(barTime, TIME_DATE | TIME_MINUTES));
Print("始値: ", DoubleToString(openPrice, Digits));
Print("高値: ", DoubleToString(highPrice, Digits));
Print("安値: ", DoubleToString(lowPrice, Digits));
Print("終値: ", DoubleToString(closePrice, Digits));
}
このコードをEAとしてコンパイルし、チャートにセットすると、「エキスパート」タブに1本前のバーの情報が表示されます。NULLと0を指定しているので、適用したチャートの通貨ペアと時間足のデータが自動的に使われます。
実践サンプル① ― 陽線・陰線を判定する
EA開発でよく使うのが「前のローソク足が陽線だったか陰線だったか」の判定です。始値と終値を比較するだけで簡単に実現できます。
//+------------------------------------------------------------------+
//| 1本前のローソク足が陽線か陰線かを判定 |
//+------------------------------------------------------------------+
void OnTick()
{
double prevOpen = iOpen(Symbol(), 0, 1);
double prevClose = iClose(Symbol(), 0, 1);
if(prevClose > prevOpen)
{
// 陽線(終値 > 始値)
Print("1本前は陽線です(上昇)");
}
else if(prevClose < prevOpen)
{
// 陰線(終値 < 始値)
Print("1本前は陰線です(下降)");
}
else
{
// 同値(十字線など)
Print("1本前は同値線です");
}
}
「2本連続で陽線なら買いエントリー」といった条件も、shift=1とshift=2を使って簡単に書けます。
実践サンプル② ― 直近N本の最高値・最安値を求める
forループとiHigh/iLowを組み合わせれば、直近N本のバーの中から最高値・最安値を見つけることができます。
//+------------------------------------------------------------------+
//| 直近N本のバーから最高値・最安値を算出 |
//+------------------------------------------------------------------+
void OnTick()
{
int lookback = 20; // 過去20本分を調べる
double highest = 0;
double lowest = 999999;
for(int i = 1; i <= lookback; i++)
{
double h = iHigh(NULL, 0, i);
double l = iLow(NULL, 0, i);
if(h > highest) highest = h;
if(l < lowest) lowest = l;
}
Print("直近", lookback, "本の最高値: ", DoubleToString(highest, Digits));
Print("直近", lookback, "本の最安値: ", DoubleToString(lowest, Digits));
}
※ブレイクアウト戦略やレンジ判定のロジックに応用できます。
実践サンプル③ ― マルチタイムフレーム(MTF)で上位足の値を取得
「チャートの時間足を切り替えても、常に4時間足のオープン時間を取得したい!」という場合にはiTime()関数を使用して引数に「PERIOD_H4」を渡してあげる必要があります。また、EAやインジケーターを適用したチャートの通貨ペアはUSD/JPYだが、取得したい情報がEUR/JPYのものである場合でもiTime()関数が活躍します。これは他のiClose()、iHigh()なども同様です。
//+------------------------------------------------------------------+
//| 5分足チャート上から日足・4時間足のデータを取得する例 |
//+------------------------------------------------------------------+
void OnTick()
{
// 日足の1本前の終値
double dailyClose = iClose(NULL, PERIOD_D1, 1);
// 4時間足の1本前の高値
double h4High = iHigh(NULL, PERIOD_H4, 1);
// 4時間足の1本前の安値
double h4Low = iLow(NULL, PERIOD_H4, 1);
// 日足の1本前の開始時刻
datetime dailyTime = iTime(NULL, PERIOD_D1, 1);
Print("前日の終値: ", DoubleToString(dailyClose, Digits));
Print("前日の開始時刻: ", TimeToString(dailyTime, TIME_DATE));
Print("4H前回バーの高値: ", DoubleToString(h4High, Digits));
Print("4H前回バーの安値: ", DoubleToString(h4Low, Digits));
}
たとえば5分足チャート上で「前日の高値・安値」をラインとして引いたり、「4時間足が上昇トレンドなら5分足で押し目買いだけを行う」といったMTFロジックを組むときに活躍します。
定義済み配列 Open[] / Close[] / High[] / Low[] / Time[] との違い
MQL4には、i〇〇()関数とは別に、Open[]、Close[]、High[]、Low[]、Time[]という定義済み配列も用意されています。EA等を適用したチャートにおける終値は定義済み配列であるClose[]に格納されており、EA等を適用したチャートにおける終値を取得したい場合はClose[]を使用し、EA等を適用したチャート以外の通貨ペアや時間軸における終値を取得したい場合はiClose()関数を使用します。使い分けのポイントは次のとおりです。
| 定義済み配列 (例: Close[1]) |
i〇〇()関数 (例: iClose(NULL,0,1)) |
|
|---|---|---|
| 通貨ペア | チャートの通貨ペアのみ | 任意の通貨ペアを指定可能 |
| 時間足 | チャートの時間足のみ | 任意の時間足を指定可能 |
| 記述の簡潔さ | 短くシンプル | 引数が3つ必要 |
| MTF対応 | × | ○ |
なお、iClose(NULL, 0, 1)とClose[1]は同じ値を返します。どちらを使っても結果は同じですが、後からMTF対応に拡張する可能性がある場合は、最初からi〇〇()関数で書いておくと修正が楽です。
よくある注意点・落とし穴
shift=0 は未確定のバー
iClose(NULL, 0, 0) で取得できる終値は、現在形成中のバーの最新価格です。ティックが入るたびに値が変わるため、売買判断には確定済みのshift=1を使うのが安全です。
ローカル履歴がない場合は0が返る
ローカル履歴がない(読み込まれていない)場合、関数は0を返します。特にマルチタイムフレームや他通貨ペアのデータを使う場合は、事前にヒストリーデータを取得しておきましょう。
Symbol()を使おう
通貨ペア名は"USDJPY"のように直接書くこともできますが、Symbol()やNULLを使えば、どのチャートにセットしても自動的にそのチャートの通貨ペアが適用されるので、汎用性の高いEAが作れます。
まとめ
今回学んだ5つの時系列アクセス関数をおさらいしましょう。
iOpen(symbol, timeframe, shift)→ 始値を取得iClose(symbol, timeframe, shift)→ 終値を取得iHigh(symbol, timeframe, shift)→ 高値を取得iLow(symbol, timeframe, shift)→ 安値を取得iTime(symbol, timeframe, shift)→ バーの形成開始時刻を取得
すべて同じ3つの引数(通貨ペア・時間軸・バー位置)で統一されているため、1つ覚えれば残りもすぐに使えます。
これらの関数は、陽線・陰線の判定、ブレイクアウト戦略、マルチタイムフレーム分析など、EA開発のあらゆる場面で必要になります。ぜひサンプルコードを実際にMT4のMetaEditorに入力して動かし、手を動かしながら身につけていきましょう!

