1. MQL5の iBands とは何か
iBands は、MQL5でボリンジャーバンド(Bollinger Bands)を取得するための標準関数です。
MetaTrader 5(MT5)では、テクニカル指標の値をEA(自動売買プログラム)やスクリプトから取得する場合、インジケータハンドル(indicator handle:指標の計算結果へアクセスする識別番号)を作成し、そのハンドルを使ってデータを読み取る仕組みになっています。
一般的な処理の流れは次のとおりです。
iBands でボリンジャーバンドのインジケータハンドルを作成
CopyBuffer でバンド値を取得
- 取得した値を売買ロジックに使用
この構造は、MQL4のインジケータ取得方法と大きく異なる点です。
MQL4ではインジケータ関数を呼ぶだけで値を取得できましたが、MQL5では次のような2段階の仕組みになっています。
この違いを理解していないと、初心者は次のような問題に直面します。
よくある失敗
iBands を呼んだだけで値が取得できると思ってしまう
CopyBuffer を使わずにバンド値を取得しようとする
OnTick() 内で毎回 iBands を作成してしまい、EAが重くなる
特に3つ目のミスは、EAのパフォーマンス低下の原因になります。
インジケータハンドルは通常 OnInit() で一度だけ作成するのが基本です。
1.1 ボリンジャーバンド(Bollinger Bands)の基本
ボリンジャーバンドは、価格の変動幅(ボラティリティ)を可視化するテクニカル指標です。
ジョン・ボリンジャーによって考案され、トレードでは非常に広く使われています。
ボリンジャーバンドは次の3つのラインで構成されます。
| ライン |
内容 |
| 中央線 |
移動平均(通常はSMA) |
| 上バンド |
移動平均 + 標準偏差 |
| 下バンド |
移動平均 – 標準偏差 |
ここでの 標準偏差とは、価格が平均値からどれくらい離れているかを示す統計値です。
つまり、ボリンジャーバンドは次のような特徴を持ちます。
- 相場のボラティリティが高い → バンドが広がる
- 相場が静かな → バンドが狭くなる
この特性を利用して、トレードでは次のような判断が行われます。
代表的な利用方法
- 上バンド付近 → 買われ過ぎ
- 下バンド付近 → 売られ過ぎ
- バンド拡張 → トレンド発生
- バンド収縮 → レンジ相場
ただし、これらは絶対的な売買シグナルではありません。
市場環境や時間足によって挙動は大きく変わるため、EA開発では他の指標と組み合わせて使用することが一般的です。
1.2 EA開発での主な用途
MQL5で iBands を使う目的は、ボリンジャーバンドを利用した売買ロジックの実装です。
EAでは主に次のような用途で使われます。
逆張り戦略
価格がバンドの外側に到達した場合、行き過ぎと判断して反転を狙う方法です。
例
この戦略はレンジ相場で有効な場合が多いですが、強いトレンドでは機能しないことがあります。
ブレイクアウト戦略
バンドの外側へ価格が突破した場合、トレンドの開始と判断する方法です。
例
この手法はトレンドフォロー型EAでよく使われます。
ボラティリティ判定
バンド幅を計算することで、相場の状態を判断できます。
例
- バンド幅が狭い → 相場が静か
- バンド幅が拡大 → トレンド開始の可能性
この情報は、次のような用途に使われます。
- トレード開始タイミング
- ロットサイズ調整
- トレード停止フィルター
注意点(初心者がよく誤解する点)
ボリンジャーバンドは方向を示す指標ではありません。
あくまで「価格の変動幅」を示す指標です。
そのため、次のような誤解がよくあります。
よくある誤解
- 上バンド到達 = 必ず下がる
- 下バンド到達 = 必ず上がる
実際には、強いトレンドではバンド沿いに価格が動き続けることもあります。
EAロジックでは、RSIやATRなどの他指標と組み合わせることが多いです。
2. iBands の構文(シンタックス)とパラメータ
iBands は、ボリンジャーバンドインジケータのハンドル(識別番号)を作成する関数です。
この関数を実行すると、MetaTrader内部でボリンジャーバンドの計算インジケータが生成され、そのハンドル(整数値)が返されます。
このハンドルは、その後 CopyBuffer を使ってバンド値を取得するために使用します。
MQL5での基本構文は次の通りです。
int iBands(
string symbol,
ENUM_TIMEFRAMES period,
int bands_period,
int bands_shift,
double deviation,
ENUM_APPLIED_PRICE applied_price
);
戻り値
- 成功:インジケータハンドル(0以上の整数)
- 失敗:
INVALID_HANDLE
そのため、EAでは通常次のようにエラーチェックを行います。
int bandsHandle = iBands(_Symbol, PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
if(bandsHandle == INVALID_HANDLE)
{
Print("iBandsの作成に失敗しました");
}
このエラーチェックを行わないと、後続の CopyBuffer で原因不明のエラーが発生することがあります。
2.1 各パラメータの意味
iBands には6つのパラメータがあります。
それぞれの意味を理解しておくことは、EA開発では非常に重要です。
| パラメータ |
内容 |
| symbol |
通貨ペア(例:EURUSD) |
| period |
時間足 |
| bands_period |
移動平均期間 |
| bands_shift |
バンドのシフト |
| deviation |
標準偏差 |
| applied_price |
使用する価格 |
以下で個別に解説します。
symbol(通貨ペア)
インジケータを計算する通貨ペアを指定します。
例
_Symbol
これは「現在のチャートの通貨ペア」を意味します。
例
iBands("EURUSD", PERIOD_CURRENT, 20, 0, 2.0, PRICE_CLOSE);
複数通貨EAでは、異なる通貨ペアを指定することも可能です。
注意点
- 通貨名を間違えると INVALID_HANDLE になります
- ブローカーによっては EURUSD.m のような接尾辞が付く場合があります
period(時間足)
ボリンジャーバンドを計算する時間足です。
主な指定方法
PERIOD_CURRENT
PERIOD_M1
PERIOD_M5
PERIOD_M15
PERIOD_H1
PERIOD_D1
例
PERIOD_H1
これは1時間足のボリンジャーバンドを意味します。
よくあるミス
- EAの時間足とインジケータ時間足を混同する
- マルチタイムフレーム処理を理解せず使う
初心者はまず
PERIOD_CURRENT
を使うと安全です。
bands_period(移動平均期間)
中央線の移動平均期間です。
例
20
これは一般的なボリンジャーバンド設定です。
代表的な設定
| 期間 |
用途 |
| 20 |
一般的 |
| 14 |
短期トレード |
| 50 |
中期トレンド |
期間が小さいほど、反応が速いがノイズが増えます。
bands_shift(バンドシフト)
インジケータの表示位置を右へずらす値です。
通常は
0
を使用します。
この値は主にチャート表示の都合のためのものであり、EAロジックではほとんど使用されません。
初心者は 0固定で問題ありません。
deviation(標準偏差)
バンド幅を決める標準偏差倍率です。
代表例
2.0
これは最も一般的な設定です。
例
| deviation |
特徴 |
| 1.0 |
狭いバンド |
| 2.0 |
標準 |
| 3.0 |
非常に広い |
値が大きいほど、バンドは広くなります。
applied_price(適用価格)
インジケータ計算に使う価格の種類です。
主な値
PRICE_CLOSE
PRICE_OPEN
PRICE_HIGH
PRICE_LOW
PRICE_MEDIAN
PRICE_TYPICAL
PRICE_WEIGHTED
初心者は通常
PRICE_CLOSE
を使用します。
これは終値ベースのボリンジャーバンドです。
2.2 iBands を使う基本コード
EAでは通常、OnInit() でハンドルを作成します。
例
int bandsHandle;
int OnInit()
{
bandsHandle = iBands(
_Symbol,
PERIOD_CURRENT,
20,
0,
2.0,
PRICE_CLOSE
);
if(bandsHandle == INVALID_HANDLE)
{
Print("iBands作成エラー");
return(INIT_FAILED);
}
return(INIT_SUCCEEDED);
}
この方法により、EA起動時に1回だけインジケータを生成できます。
よくある失敗
初心者がよくやるミスをまとめます。
OnTick()で毎回iBandsを作る
// 悪い例
void OnTick()
{
int handle = iBands(...);
}
これは毎ティックでインジケータ生成するため、EAが重くなります。
エラーチェックをしない
int handle = iBands(...);
これだけでは、失敗しても気づけません。
CopyBuffer前にハンドル確認をしない
ハンドルが無効だと
array out of range
などのエラー原因になります。
3. CopyBuffer を使ってボリンジャーバンドの値を取得する方法
iBands はボリンジャーバンドの計算インジケータを生成する関数ですが、
この関数だけではバンドの値を取得することはできません。
実際に値を取得するためには、CopyBuffer 関数を使用してインジケータバッファからデータをコピーする必要があります。
MQL5では、インジケータは内部的に複数のバッファ(データ配列)を持っています。
ボリンジャーバンドの場合、次の3つのラインがそれぞれ別のバッファに格納されています。
| バッファ番号 |
内容 |
| 0 |
中央線(Middle Band / Moving Average / BASE_LINE) |
| 1 |
上バンド(Upper Band / UPPER_BAND) |
| 2 |
下バンド(Lower Band / LOWER_BAND) |
このバッファ番号を指定して CopyBuffer を呼び出すことで、
EAは任意のバンド値を取得できます。
3.1 CopyBuffer の基本構文
CopyBuffer の基本構文は次の通りです。
int CopyBuffer(
int indicator_handle,
int buffer_num,
int start_pos,
int count,
double buffer[]
);
各パラメータの意味は次の通りです。
| パラメータ |
内容 |
| indicator_handle |
iBandsで取得したハンドル |
| buffer_num |
バッファ番号 |
| start_pos |
取得開始位置 |
| count |
取得するデータ数 |
| buffer |
データ格納配列 |
戻り値
そのため、実際のEAでは戻り値チェックを行うことが重要です。
3.2 上バンドを取得するコード例
まず、上バンド(Upper Band)を取得する例を見てみます。
double upperBand[];
if(CopyBuffer(bandsHandle, 1, 0, 1, upperBand) < 0)
{
Print("CopyBufferエラー");
}
このコードの意味は次の通りです。
| パラメータ |
意味 |
| bandsHandle |
iBandsハンドル |
| 1 |
上バンド |
| 0 |
最新バー |
| 1 |
1本取得 |
結果は次のように取得できます。
double upper = upperBand[0];
3.3 下バンドと中央線を取得する方法
同じ方法で、中央線と下バンドも取得できます。
中央線(移動平均)
double middleBand[];
CopyBuffer(bandsHandle, 0, 0, 1, middleBand);
下バンド
double lowerBand[];
CopyBuffer(bandsHandle, 2, 0, 1, lowerBand);
3.4 実践的なコード例
EAでは通常、3つのバンドを同時に取得します。
double middle[1];
double upper[1];
double lower[1];
if(CopyBuffer(bandsHandle,0,0,1,middle) < 0) return;
if(CopyBuffer(bandsHandle,1,0,1,upper) < 0) return;
if(CopyBuffer(bandsHandle,2,0,1,lower) < 0) return;
double middleBand = middle[0];
double upperBand = upper[0];
double lowerBand = lower[0];
これにより、EA内でボリンジャーバンドの3ラインを使用できます。
3.5 よくある失敗と注意点
CopyBuffer は初心者が最もつまずきやすい部分です。
特に次のミスが非常に多く見られます。
配列サイズを確保していない
次のコードは危険です。
double upper[];
CopyBuffer(handle,1,0,1,upper);
配列サイズが確保されていない場合、エラーになる可能性があります。
安全な方法
double upper[1];
または
ArrayResize(upper,1);
バッファ番号を間違える
初心者が混乱しやすいポイントです。
| バッファ |
内容 |
| 0 |
中央線 |
| 1 |
上バンド |
| 2 |
下バンド |
この順番を間違えると、ロジックが完全に崩れます。
データがまだ準備されていない
EA起動直後などでは、インジケータ計算がまだ完了していない場合があります。
その場合、CopyBuffer は -1 を返します。
安全な処理
if(CopyBuffer(...) <= 0)
return;
最新バーと確定バーを混同する
start_pos = 0 は 現在進行中のバーです。
そのため、EAロジックでは次のように使う場合があります。
| start_pos |
意味 |
| 0 |
最新バー |
| 1 |
確定バー |
トレードロジックでは 確定バー(1) を使うケースも多いです。
4. EAで iBands を使う実装例
iBands は、単にボリンジャーバンドを表示するための関数ではありません。
EAでは、取得したバンド値と現在価格を比較し、売買条件を機械的に判定するための材料として使います。
ただし、ボリンジャーバンドはそれ単体で万能な売買シグナルではありません。
実務では、次のように役割を分けて使うことが多いです。
- 逆張り判定
- ブレイクアウト判定
- 相場の静かさ・荒さの判定
- エントリー禁止フィルター
このセクションでは、初心者が理解しやすいように、まずはもっとも基本的な2パターンを扱います。
- バンド到達で反転を狙う逆張り型
- バンド突破で流れに乗るブレイクアウト型
4.1 逆張りロジックの基本例
逆張り型では、価格がバンド外側まで到達したときに、行き過ぎからの戻りを狙います。
典型例は次の通りです。
- 現在価格が上バンド以上 → 売りを検討
- 現在価格が下バンド以下 → 買いを検討
コード例は次のようになります。
double upper[1];
double lower[1];
if(CopyBuffer(bandsHandle, 1, 0, 1, upper) <= 0) return;
if(CopyBuffer(bandsHandle, 2, 0, 1, lower) <= 0) return;
double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
if(bid >= upper[0])
{
Print("売りシグナル候補:価格が上バンドに到達");
}
if(ask <= lower[0])
{
Print("買いシグナル候補:価格が下バンドに到達");
}
このコードでは、まだ注文は出していません。
まずは条件判定だけをログ出力する形にしておくと、ロジック検証がしやすくなります。
4.2 ブレイクアウトロジックの基本例
ブレイクアウト型では、価格がバンド外へ出たことを勢いの発生とみなし、その方向へ追随します。
典型例は次の通りです。
- 終値が上バンドを上抜け → 買い候補
- 終値が下バンドを下抜け → 売り候補
この場合、現在進行中のバーではなく、確定したバーを使う方が安全です。
そのため、CopyBuffer では start_pos = 1 を使うことが多くなります。
double upper[1];
double lower[1];
double closePrice[1];
if(CopyBuffer(bandsHandle, 1, 1, 1, upper) <= 0) return;
if(CopyBuffer(bandsHandle, 2, 1, 1, lower) <= 0) return;
if(CopyClose(_Symbol, PERIOD_CURRENT, 1, 1, closePrice) <= 0) return;
if(closePrice[0] > upper[0])
{
Print("買いブレイク候補:確定足終値が上バンドを上抜け");
}
if(closePrice[0] < lower[0])
{
Print("売りブレイク候補:確定足終値が下バンドを下抜け");
}
この方法の利点は、未確定バーの一時的な飛び出しを除外しやすいことです。
4.3 バンド幅を使ったボラティリティ判定
ボリンジャーバンドは、上バンドと下バンドの差を取ることで、相場の変動の大きさを数値化できます。
計算式は単純です。
double bandWidth = upper[0] - lower[0];
コード例は次の通りです。
double upper[1];
double lower[1];
if(CopyBuffer(bandsHandle, 1, 1, 1, upper) <= 0) return;
if(CopyBuffer(bandsHandle, 2, 1, 1, lower) <= 0) return;
double bandWidth = upper[0] - lower[0];
if(bandWidth < 0.0010)
{
Print("バンド幅が小さいため見送り");
}
else
{
Print("バンド幅が十分あるため売買候補");
}
5.2 CopyBuffer が失敗する原因
iBands が正常でも、CopyBuffer が必ず成功するわけではありません。
MQL5では、インジケータ計算がまだ準備できていない段階で CopyBuffer を呼ぶと失敗することがあります。
たとえば次のコードは、戻り値チェックがないため危険です。
double upper[1];
CopyBuffer(bandsHandle, 1, 0, 1, upper);
double value = upper[0];
この場合、コピー失敗時でもそのまま upper[0] を使ってしまい、
ロジック異常や誤判定の原因になります。
安全な書き方は次の通りです。
double upper[1];
if(CopyBuffer(bandsHandle, 1, 0, 1, upper) <= 0)
{
Print("上バンドの取得に失敗");
return;
}
5.3 バッファ番号の取り違え
iBands は3本のラインを扱いますが、
初心者が最も混乱しやすいのがバッファ番号の順番です。
MQL5公式ドキュメントでは、iBands のバッファ番号は次の通りです。
| バッファ番号 |
内容 |
| 0 |
中央線(BASE_LINE) |
| 1 |
上バンド(UPPER_BAND) |
| 2 |
下バンド(LOWER_BAND) |
ここを逆に覚えると、ロジックはコンパイル上問題なく動いても、売買判定が完全に誤る可能性があります。
たとえば、本来は上バンド判定のつもりで buffer_num = 0 を指定すると、
実際には中央線を比較してしまい、エントリー条件が別物になります。
ありがちな状況
- 上バンドと中央線を取り違える
- コードコメントと実際のバッファ番号が一致していない
- 他記事や過去コードを流用して順番が混在する
この種のミスは、見た目では気付きにくいのが厄介です。
デバッグ時は、取得した3本の値をログへ出力し、上下関係が正しいか確認すると安全です。
Print("Upper=", upper[0], " Middle=", middle[0], " Lower=", lower[0]);
5.4 未確定バーと確定バーの混同
CopyBuffer で start_pos = 0 を指定すると、現在進行中のバーを取得します。
一方、start_pos = 1 は直近で確定したバーです。
この違いは、EAロジックでは非常に重要です。
start_pos = 0 の特徴
- リアルタイム性が高い
- 値が刻々と変わる
- シグナルの先出しができる
- ダマシも増えやすい
start_pos = 1 の特徴
- バー確定後の値を使える
- ロジックが安定しやすい
- バックテストと実運用の差が出にくい
たとえば次のように明確に使い分けます。
// 未確定バーの上バンドを見る
CopyBuffer(bandsHandle, 1, 0, 1, upper);
// 確定バーの上バンドを見る
CopyBuffer(bandsHandle, 1, 1, 1, upper);
実運用を安定させたい場合は、まず確定バー基準から始めるのが無難です。
6.2 バッファ番号の理解が曖昧なまま使う
iBands は3本のラインを持つため、どのバッファがどのラインかを正しく理解していないと、ロジック全体が崩れます。
MQL5公式ドキュメントでは、次の対応になっています。
| バッファ番号 |
内容 |
| 0 |
中央線(BASE_LINE) |
| 1 |
上バンド(UPPER_BAND) |
| 2 |
下バンド(LOWER_BAND) |
ここで起きやすい失敗は次の通りです。
- 上バンドと中央線を混同する
- 中央線と下バンドを混同する
- コードコメントと実際の番号が一致していない
このミスの厄介な点は、コードが正常に動いて見えることです。
コンパイルエラーにもならず、CopyBuffer() も成功するため、見落としやすくなります。
実務での確認方法
取得後にログへ出して、数値の大小関係を確認します。
Print("Upper=", upper[0], " Middle=", middle[0], " Lower=", lower[0]);
通常は、同一バーで
となるはずです。
この関係が崩れているなら、バッファ指定やデータ取得方法を見直すべきです。
6.3 配列の扱い方を曖昧にしてしまう
CopyBuffer() は配列へデータをコピーする関数です。
そのため、配列の準備や参照方法を曖昧にしたまま使うと、誤動作やエラーの原因になります。
代表的な失敗は次の通りです。
- 配列サイズを意識せずに使う
- 何本取得したのか分からないまま参照する
[0] が常に「最新確定足」だと思い込む
たとえば次のコードです。
double upper[];
CopyBuffer(bandsHandle, 1, 0, 1, upper);
Print(upper[0]);
これは環境によっては動くこともありますが、
常に安全とは言えません。初心者はまず、サイズを明示した方が安全です。
double upper[1];
if(CopyBuffer(bandsHandle, 1, 0, 1, upper) <= 0)
return;
Print(upper[0]);
また、複数本取得する場合は、どのインデックスがどのバーかを明確に意識する必要があります。
double upper[3];
CopyBuffer(bandsHandle, 1, 0, 3, upper);
7.2 iBands のバッファ番号はどう対応していますか?
ボリンジャーバンドは3つのラインで構成されており、それぞれ次のバッファ番号に対応します。
| バッファ番号 |
内容 |
| 0 |
中央線(Middle Band / 移動平均 / BASE_LINE) |
| 1 |
上バンド(Upper Band / UPPER_BAND) |
| 2 |
下バンド(Lower Band / LOWER_BAND) |
CopyBuffer の第2引数にこの番号を指定することで、目的のラインを取得できます。
7.3 iBands はどこで作成するのが適切ですか?
通常は OnInit() 内で一度だけ作成するのが推奨されます。
OnTick() 内で毎回 iBands を作成すると、ティックごとにインジケータを生成することになり、
EAの処理が重くなったり、挙動が不安定になる可能性があります。
7.4 CopyBuffer の start_pos は何を意味しますか?
start_pos は、どのバー位置からデータを取得するかを指定する値です。
| start_pos |
意味 |
| 0 |
現在進行中のバー |
| 1 |
直近確定バー |
| 2 |
その1本前のバー |
リアルタイムの変動を含めたくない場合は、確定バー(1)を使用する方が安定します。
7.5 CopyBuffer が失敗するのはなぜですか?
主な原因は次の通りです。
- インジケータハンドルが無効
- バー履歴がまだ読み込まれていない
- バッファ番号の指定ミス
- インジケータ計算が完了していない
そのため、CopyBuffer の戻り値を必ず確認し、取得失敗時は処理を中断するようにするのが安全です。
7.6 ボリンジャーバンドに触れたら必ず反転しますか?
必ずしも反転するわけではありません。
ボリンジャーバンドは価格の変動幅(ボラティリティ)を示す指標であり、
トレンド方向そのものを保証する指標ではありません。
強いトレンドでは、価格がバンド沿いに動き続ける(バンドウォーク)こともあります。
そのため、EAでは次のような補助条件を組み合わせることが一般的です。
7.7 バンド幅はどのように計算しますか?
ボリンジャーバンドの幅は、上バンドと下バンドの差で計算できます。
double bandWidth = upper[0] - lower[0];
この値を利用すると、次のような判断が可能になります。
- バンド幅が狭い → 相場が停滞している可能性
- バンド幅が広い → 相場が活発な可能性
ただし、通貨ペアや価格桁数によって値のスケールが異なるため、
固定値の閾値は環境によって調整が必要です。
7.8 iBands と iCustom の違いは何ですか?
iBands は MetaTraderに標準搭載されているボリンジャーバンドインジケータを呼び出す関数です。
一方 iCustom は、自作または外部のカスタムインジケータを呼び出す関数です。
標準ボリンジャーバンドを使う場合は iBands の方がシンプルで扱いやすく、
カスタム計算ロジックを使う場合は iCustom を使用します。