「ボリンジャーバンドを使ったEAを作ってみたい」
「MT4のiBands()を使って売買条件を作る方法を知りたい」
そんな方向けに、この記事ではボリンジャーバンドを使ったMT4 EAの作り方を、MQL4のサンプルコード付きで解説します。
今回作るのは、単純に「±2σへ触れたら逆張り」するEAではありません。
価格が3σを突破するほど強く動いた方向を記録し、その後2σの内側へ戻ったタイミングで同じ方向へエントリーする順張りEAです。
ボリンジャーバンドの取得にはMQL4標準のiBands()を使用します。
EA本体も無料でダウンロードできるので、コードを見ながらMT4で動作を確認できます。
- ボリンジャーバンド期間:20
- 上側3σ突破 → 2σ内へ戻る → BUY
- 下側3σ突破 → 2σ内へ戻る → SELL
- 判定はTickごとに実行
- 決済は固定TP・SL
- 1ポジションのシンプルな学習用構成
ボリンジャーバンドEAの売買ロジック
今回のEAでは、3σを突破した方向へすぐエントリーするのではなく、一度待機状態に入ります。
その後、価格が±2σの内側へ戻ったところで、最初に3σを突破した方向へエントリーします。

BUYエントリー条件
① 価格が上側3σを突破
② BUY待機状態として記録
③ 価格が±2σの内側へ戻る
④ BUYエントリー
SELLエントリー条件
① 価格が下側3σを突破
② SELL待機状態として記録
③ 価格が±2σの内側へ戻る
④ SELLエントリー
つまり、今回のEAは「バンドに触れたら売買する」のではなく、3σまで大きく動いた方向を記憶し、その後の戻りを待って同方向へ入るロジックです。
3σ突破から2σ内へ戻るまでの状態を保持するため、グローバル変数waitBBを使用しています。
このEAはTickごとに判定する
今回のボリンジャーバンドEAは、ローソク足確定時だけではなく価格が更新されるたびにOnTick()で判定します。
これは、ローソク足の途中で3σを突破した動きを記録し、その後2σ内へ戻る流れを判定するためです。
ベースEAテンプレートからの変更点
今回のEAも、当サイトで公開しているMT4 EAベーステンプレートをもとに作成しています。
ベーステンプレートからの主な変更点は次の通りです。
BB_KIKANを追加してボリンジャーバンド期間を設定iBands()で2σ・3σの上下バンドを取得waitBBで3σを突破した方向を記録- 2σ内へ戻ったタイミングでBUY / SELLを判定
- 新しいローソク足による1回制御は使用せず、Tick単位で判定
- 決済条件は追加せず、固定TP / SLのみ使用
- 今回使用しない注文変更・一括決済関数は掲載しない
学習用サンプルとして売買ロジックを追いやすくするため、今回のEAで実際に使用する処理だけを残しています。
ボリンジャーバンドEAを無料ダウンロード
記事で解説しているボリンジャーバンドEAを無料でダウンロードできます。
📥 ボリンジャーバンドEAをダウンロード無料MT4 EAビルダーでは、ボリンジャーバンドを使った売買条件も画面上で設定してEAを作成できます。
今回のサンプルを試したあと、条件を変えて自分のEAを作ってみたい方にもおすすめです。
▶ 無料MT4 EAビルダーを使ってみる
初めて使用する場合は、まずデモ口座やストラテジーテスターで動作を確認してください。
ボリンジャーバンドEAのMQL4サンプルコード
以下が今回の公開版ソースコードです。
公開表記はv1.0、ソース上は#property version "1.00"としています。
背景色が付いている行が、ベースEAテンプレートから主に変更・追加した部分です。
共通の注文処理はそのまま利用し、ボリンジャーバンド固有の処理を中心に強調しています。
//+------------------------------------------------------------------+
//| 02_BollingerBands.mq4 |
//| Copyright © 2020-2026 ぷろぐらむFX |
//| https://fx-prog.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright © 2020-2026 ぷろぐらむFX"
#property link "https://fx-prog.com/"
#property version "1.00"
#property strict
input double Lots = 0.01; //ロット
input int TP = 100; //利確(pips)
input int SL = 100; //損切り(pips)
//***【パラメータ設定↓】***//
input int BB_KIKAN = 20; //ボリンジャーバンド期間
//***【パラメータ設定↑】***//
int waitBB = 0; //0=待機なし / 1=BUY待機 / -1=SELL待機
string Ea_Name = WindowExpertName(); //EA名称をオーダーコメントに使用
double PipValue; //ブローカー桁数に対応したPoint補正
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
if(Digits == 3 || Digits == 5){
PipValue = Point * 10;
}else{
PipValue = Point;
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
//ポジション保有中は新規判定を行わない
if(OrdersTotal() > 0){
waitBB = 0;
return;
}
int ea_order_Type = -1;
double ea_order_stop_price = 0;
double ea_order_good_price = 0;
//***【新規注文判断↓】***//
//現在足のボリンジャーバンドを取得
double BB3UP = iBands(NULL,0,BB_KIKAN,3,0,PRICE_CLOSE,MODE_UPPER,0);
double BB3LO = iBands(NULL,0,BB_KIKAN,3,0,PRICE_CLOSE,MODE_LOWER,0);
double BB2UP = iBands(NULL,0,BB_KIKAN,2,0,PRICE_CLOSE,MODE_UPPER,0);
double BB2LO = iBands(NULL,0,BB_KIKAN,2,0,PRICE_CLOSE,MODE_LOWER,0);
//3σを突破した方向を記録
if(Ask > BB3UP){
waitBB = 1;
}else if(Bid < BB3LO){
waitBB = -1;
}
//3σ突破後、価格が±2σの内側へ戻ったら同方向へエントリー
bool inside2Sigma = (Ask < BB2UP && Bid > BB2LO);
if(waitBB == 1 && inside2Sigma){
ea_order_Type = OP_BUY;
}else if(waitBB == -1 && inside2Sigma){
ea_order_Type = OP_SELL;
}
//***【新規注文判断↑】***//
//***【TP/SL判断↓】***//
if(ea_order_Type == OP_BUY){
ea_order_stop_price = Ask - SL * PipValue;
ea_order_good_price = Ask + TP * PipValue;
}else if(ea_order_Type == OP_SELL){
ea_order_stop_price = Bid + SL * PipValue;
ea_order_good_price = Bid - TP * PipValue;
}
//***【TP/SL判断↑】***//
if(ea_order_Type > -1){
bool orderResult = funcOrder_Send(ea_order_Type,ea_order_stop_price,ea_order_good_price,Lots,Ea_Name,0,0);
//注文成功後に待機状態を解除
if(orderResult){
waitBB = 0;
}
}
}
//★★★★★★★★★★★★★★★★★★★★ ここから下は共通関数 ★★★★★★★★★★★★★★★★★★★★
//+------------------------------------------------------------------+
//|【関数】新規注文関数 |
//|【引数】orderType:売買(0=BUY, 1=SELL) |
//|【引数】sl:損切り価格 tp:利確価格 |
//|【引数】lots:取引ロット数 |
//|【引数】orderComment:オーダーコメント |
//|【引数】magic:MagicNumber |
//|【引数】maxSpreadPoints:許容スプレッド[Point] (0=制限なし) |
//|【戻値】true=成功 false=失敗 |
//+------------------------------------------------------------------+
bool funcOrder_Send(int orderType, double sl, double tp, double lots, string orderComment, int magic, int maxSpreadPoints){
int ticket = -1;
double price = 0;
double spread = 0;
color clr = clrNONE;
//最大10回リトライ
for(int retry=0; retry<10; retry++){
RefreshRates();
spread = MarketInfo(Symbol(),MODE_SPREAD);
//スプレッドチェック
if(maxSpreadPoints > 0 && spread > maxSpreadPoints){
Print("スプレッド拡大中(",spread,"ポイント) → 待機中 (リトライ=",retry+1,")");
Sleep(2000);
continue;
}
//注文価格を取得
if(orderType == OP_BUY){
price = Ask;
clr = clrBlue;
}else if(orderType == OP_SELL){
price = Bid;
clr = clrRed;
}else{
Print("funcOrder_Send: 未対応の注文種別=",orderType);
return false;
}
price = NormalizeDouble(price,Digits);
if(sl > 0) sl = NormalizeDouble(sl,Digits);
if(tp > 0) tp = NormalizeDouble(tp,Digits);
ResetLastError();
ticket = OrderSend(Symbol(),orderType,lots,price,20,sl,tp,orderComment,magic,0,clr);
if(ticket > 0){
Print("新規注文成功! チケットNo=",ticket," レート=",price," Lots=",lots," スプレッド=",spread,"ポイント");
return true;
}
int err = GetLastError();
Print("新規注文失敗 エラーNo=",err," リトライ回数=",retry+1);
Sleep(2000);
}
return false;
}MQL4コードのポイントを解説
iBands()でボリンジャーバンドを取得する
MQL4では、iBands()を使ってボリンジャーバンドの値を取得できます。
iBands(NULL,0,20,3,0,PRICE_CLOSE,MODE_UPPER,0);
主な引数は次の意味です。
| 引数 | 今回の値 | 意味 |
|---|---|---|
| symbol | NULL | 現在のチャートの通貨ペア |
| timeframe | 0 | 現在のチャート時間足 |
| period | BB_KIKAN | ボリンジャーバンド期間 |
| deviation | 2 または 3 | 2σ・3σを指定 |
| bands_shift | 0 | バンドの表示シフト |
| applied_price | PRICE_CLOSE | 終値を計算対象に使用 |
| mode | MODE_UPPER / MODE_LOWER | 上側・下側バンドを指定 |
| shift | 0 | 現在足のバンド値を取得 |

MODE_UPPERとMODE_LOWERで上下バンドを取得する
今回のEAでは中央線は使用せず、2σと3σそれぞれの上側・下側バンドを取得しています。

上側バンドはMODE_UPPER、下側バンドはMODE_LOWERを指定します。中央線が必要なロジックではMODE_MAINを使用できます。
waitBBで3σを突破した方向を記録する
int waitBB = 0; //0=待機なし / 1=BUY待機 / -1=SELL待機
3σを突破してから2σ内へ戻るまでには時間差があるため、1回の条件判定だけでは処理できません。
そこでwaitBBを使い、上側3σを突破した場合は1、下側3σを突破した場合は-1として状態を保持しています。
if(Ask > BB3UP){
waitBB = 1;
}else if(Bid < BB3LO){
waitBB = -1;
}2σ内へ戻ったらエントリーする
bool inside2Sigma = (Ask < BB2UP && Bid > BB2LO);
現在価格が上側2σより下、かつ下側2σより上にあれば、価格が±2σの内側へ戻ったと判定します。
その時点でwaitBBがBUY待機ならBUY、SELL待機ならSELLを選択します。
注文が成功してから待機状態を解除する
今回の公開版では、funcOrder_Send()が成功したことを確認してからwaitBBを0へ戻します。
if(orderResult){
waitBB = 0;
}注文前に待機状態を解除してしまうと、何らかの理由で注文に失敗した場合に、すでに発生した売買シグナルを失うためです。
決済はTP・SLで管理する
このEAには、ボリンジャーバンドを使った独自の決済条件は入れていません。
新規注文時にTPとSLを設定し、その価格へ到達した場合に決済します。そのため、個別の成行決済関数や注文変更関数は今回の公開ソースから削除しています。
新規注文は共通関数funcOrder_Send()を使用
新規注文部分には、当サイトのEAサンプルで使用している共通のfuncOrder_Send()を利用しています。
今回の記事ではボリンジャーバンドの売買ロジックを追いやすくするため、新規注文で使用する関数だけを残しています。
ボリンジャーバンドEAのパラメータ設定
公開版の基本パラメータは次の通りです。
| パラメータ | 初期値 | 内容 |
|---|---|---|
| Lots | 0.01 | 取引ロット数 |
| TP | 100 | 利確幅(pips) |
| SL | 100 | 損切り幅(pips) |
| BB_KIKAN | 20 | ボリンジャーバンドの計算期間 |
ソースコード・ダウンロード版ともに、基本初期値はLots 0.01 / TP 100 / SL 100 / BB期間20で統一しています。
後ほど掲載するバックテストではTP・SLを28pipsへ変更していますが、これはバックテスト時の設定であり、公開版の初期値とは分けています。
ボリンジャーバンドEAをカスタマイズする例
3σ突破時にそのままエントリーする場合
標準版は「3σ突破 → 2σ内へ戻る → エントリー」ですが、3σを突破した時点でそのまま順張りする形にも変更できます。
その場合はwaitBBによる待機処理と2σ内への戻り判定を使わず、3σ突破を直接売買条件にします。
if(Ask > BB3UP){
ea_order_Type = OP_BUY;
}else if(Bid < BB3LO){
ea_order_Type = OP_SELL;
}ただし、これは標準版とはエントリータイミングが変わるため、別ロジックとしてバックテストし直す必要があります。
確定足判定へ変更する場合
今回のEAはTick判定を前提にしています。単純に「新しいローソク足で1回だけ実行する処理」を追加すると、ローソク足途中の3σ突破を検出できなくなる場合があります。
確定足だけで売買したい場合は、3σ突破判定と2σ内への戻り判定を確定足ベースで組み直し、別ロジックとして検証するのがおすすめです。
ADXなどを追加して相場を絞り込む
今回のEAはボリンジャーバンドだけを使用したシンプルなサンプルです。
より条件を増やしたい場合は、ADXなどを追加してトレンドの強さをフィルターする方法もあります。
👉 MT4でADXを使ったEAの作り方|トレンド判定ロジック解説
👉 MT4でADX連携ボリンジャーバンドEAを作成|順張り特化MQL4サンプル解説
ボリンジャーバンドEAのバックテスト結果
最新版の公開ソースをもとに、USDJPYの1時間足で約2年間のバックテストを行いました。
公開版の初期値はBB期間20 / TP100 / SL100ですが、今回のバックテストではBB期間21 / TP60 / SL30へ変更しています。
TP60pips・SL30pipsとしているため、今回のテスト条件ではリスクリワード1:2です。
バックテスト条件
| 項目 | 条件 |
|---|---|
| 通貨ペア | USDJPY |
| 時間足 | H1 |
| 期間 | 2024/08/01 ~ 2026/07/31 |
| モデル | Every tick |
| モデリング品質 | 90.00% |
| 初期証拠金 | 1,000,000円 |
| スプレッド | 5 |
| Lots | 0.01 |
| BB期間 | 21 |
| TP | 60pips |
| SL | 30pips |
バックテスト結果
| 純益 | PF | 勝率 | 最大DD | 総取引数 |
|---|---|---|---|---|
| +19,269.60円 | 1.49 | 42.61% | 3,334.48円 (0.33%) | 230回 |
不整合チャートエラーは0でした。
約2年間のテストでは、PF1.49、勝率42.61%、最大ドローダウン0.33%となりました。
勝率は50%を下回っていますが、TP60pips・SL30pipsのリスクリワード1:2とすることで、利益を伸ばす結果となっています。
今回の結果から、3σ突破後の戻りを利用したボリンジャーバンド順張りロジックでも、利確・損切り幅を含めた条件を調整することで十分に利益を狙えることが分かります。
パラメータやテスト期間を変更すると結果も変わるため、実際に利用する場合はご自身の環境でもバックテスト・デモ確認を行ってください。
まとめ|iBands()を使ってボリンジャーバンドEAを作れる
今回は、MQL4のiBands()を使ってボリンジャーバンドEAを作成しました。
標準版のロジックは、3σを突破した方向を記録し、その後価格が2σ内へ戻ったところで同方向へエントリーするシンプルな順張り型です。
ボリンジャーバンドの値そのものはiBands()で簡単に取得できるため、期間・σ・エントリー位置を変更するだけでもさまざまなロジックを試せます。
まずは今回のサンプルをそのまま動かして、「3σ突破を記憶する → 2σへ戻る → エントリーする」という、状態を保持するEAの作り方を確認してみてください。







コメント
勉強させてもらってます。ありがとうございます。
SL=28, TP=28にすると同じようなバックテスト結果になるのですが、Pipsの計算が変わったりしているのでしょうか?
masa さん。
記事を見て頂きましてありがとうございます。返信が遅れてしまいました。
ご質問の件ですが、すこしソースコードを修正しておりまして現在はSTとTPは28で同じような結果になると思います。
※元々280で28pips設定でしたが、28で28pipsになるよう修正しました。