【初級編】ボリバン+移動平均線でEAを作ってみよう — AIに日本語で伝えるだけ
前回の体験を活かして、今度は自分で考えてみよう
AIで自分だけの最強EAをつくろうでは、AIにプロンプトを渡すだけでEAが作れることを紹介しました。
今回はもう一歩進みます。自分で売買条件を考えて、それをAIに日本語で伝えてEAを作る、という体験です。
ボリンジャーバンドと移動平均線という、最もメジャーなインジケーターの組み合わせで試してみましょう。
ボリンジャーバンドと移動平均線の基本
ボリンジャーバンドとは
ボリンジャーバンド(Bollinger Bands)は、移動平均線を中心として、その上下に価格の散らばり具合(標準偏差、σ)に基づいたバンドを描くインジケーターです。
標準設定は 期間20、標準偏差2σ で、次の3本のラインから構成されます。
| ライン | 意味 |
|---|---|
| 中心線(Middle Band) | 20期間の単純移動平均(SMA20) |
| 上限バンド(Upper Band) | SMA20 + 標準偏差 × 2 |
| 下限バンド(Lower Band) | SMA20 − 標準偏差 × 2 |
統計的に言うと、価格がバンドの外に出る確率は約5%です。「バンドの外に出たら平均回帰する可能性が高い」という考え方が逆張り的なトレードの基礎になります。
TradingViewでは上部メニューの「インジケーター」から「BB」または「Bollinger Bands」で検索すると追加できます。
💡 INFO
ボリンジャーバンドの幅(バンド幅)は相場のボラティリティを表します。バンドが収縮しているときは値動きが小さく(レンジ相場)、バンドが拡張しているときは値動きが大きい(トレンド相場またはブレイクアウト直後)状態を示します。
移動平均線(SMA)とは
移動平均線(Simple Moving Average)は、指定した期間の終値を平均した値を折れ線でつないだものです。
- 期間が短いほど直近の価格動向を反映しやすく、ノイズも多い
- 期間が長いほど大局的なトレンドを示しやすく、遅行する
今回は SMA(50) を使います。50期間の移動平均線は「中期トレンドの方向を見る」インジケーターとして広く使われています。価格がSMA(50)より上にある場合は上昇トレンド中、下にある場合は下降トレンド中と判断します。
📢 CTA
TradingViewでボリンジャーバンドとSMA(50)を同時に表示して、実際の値動きとバンドの関係を目で確認しながら読み進めると理解が深まります。 TradingViewを無料で始める(PR)
売買条件を考える
では、今回のEAの条件を決めましょう。
「ボリンジャーバンドの外に出たら逆張り」というシンプルなアイデアに、移動平均線でトレンド方向のフィルターを加えます。
買いエントリー条件(上昇トレンド中の押し目買い)
- 前回確定バー(1本前の確定済みバー)の終値が BB(20,2) の下限バンドを下回っている
- かつ、前回確定バーの終値が SMA(50) より上にある
上昇トレンド中(SMA50より上)に、一時的に売られてバンド下限に触れた局面を拾いに行くイメージです。
売りエントリー条件(下降トレンド中の戻り売り)
- 前回確定バー(1本前の確定済みバー)の終値が BB(20,2) の上限バンドを上回っている
- かつ、前回確定バーの終値が SMA(50) より下にある
下降トレンド中(SMA50より下)に、一時的に買われてバンド上限まで戻した局面を売るイメージです。
決済条件
- 損切り: エントリー価格から 40pips 不利な方向
- 利確: エントリー価格から 80pips 有利な方向
ポジション管理
- ロット: 0.1(外部変数で変更可能)
- 最大同時保有ポジション: 1件
💡 INFO
損切り40pips・利確80pipsはリスクリワード比1:2の設定です。勝率が50%を下回っても、長期的にはプラスに向かいやすい比率ですが、USDJPY以外の通貨ペアで使う場合はpips換算の金額が変わる点に注意してください。
AIに渡すプロンプト
条件の整理ができました。次はこれをAIに渡すプロンプトにまとめます。以下をそのままChatGPT、Claude Code、Codexなどにコピペしてください。
以下の条件でMT4のEA(MQL4)を作成してください。
【EA名】BB_MA_EA
【使用インジケーター】
- ボリンジャーバンド: 期間20、標準偏差2σ(iBANDS関数を使用)
- 単純移動平均線: 期間50(iMA関数を使用)
【エントリー条件】
- 買い: shift=1の確定バーの終値がBBの下限バンドを下回り、かつ終値がSMA(50)より上にあるとき
- 売り: shift=1の確定バーの終値がBBの上限バンドを上回り、かつ終値がSMA(50)より下にあるとき
【決済条件】
- 損切り: エントリー価格から40pips(外部変数 StopLossPips)
- 利確: エントリー価格から80pips(外部変数 TakeProfitPips)
【ポジション管理】
- 同時保有は最大1件(買いまたは売りどちらか1件のみ)
- ロットサイズは外部変数 LotSize = 0.1
【その他要件】
- マジックナンバーを使用して、このEA専用のポジション管理をする(外部変数 MagicNumber = 20001)
- 5桁業者(小数点5桁表示)に対応したpips計算を使う
- HasPosition()という独自関数でポジション有無を確認する
- CloseAllPositions()という独自関数で全ポジションを閉じる
- 全ての変数・関数に日本語コメントを付ける
- extern変数(または input変数)でパラメーターをMT4のEA設定画面から変更できるようにする
✅ TIP
プロンプトの最後に「.mq4ファイルとして保存してください」と一言追加すると、AIがファイルごと生成してくれる場合があります。コードをコピーしてMetaEditorに貼り付ける手間が省けます。
AIが生成したMQL4コード
上記プロンプトをAIに渡すと、以下のようなコードが生成されます。AIによって細部は異なりますが、ロジックは同じです。
//+------------------------------------------------------------------+
//| BB_MA_EA.mq4 |
//| ボリンジャーバンド + SMA(50) の組み合わせEA |
//| 上昇トレンド中の押し目買い/下降トレンド中の戻り売り |
//+------------------------------------------------------------------+
#property strict
//--- 外部パラメーター(MT4のEA設定画面から変更可能)
extern int BB_Period = 20; // ボリンジャーバンドの期間
extern double BB_Deviation = 2.0; // ボリンジャーバンドの標準偏差
extern int MA_Period = 50; // 移動平均線の期間
extern double LotSize = 0.1; // ロットサイズ
extern int StopLossPips = 40; // 損切りpips数
extern int TakeProfitPips = 80; // 利確pips数
extern int MagicNumber = 20001; // このEA専用のマジックナンバー
extern int Slippage = 3; // 許容スリッページ(pips)
//--- pips単位の計算に使う係数(5桁業者対応)
double PipValue;
//+------------------------------------------------------------------+
//| 初期化関数 — EA起動時に1回だけ実行される |
//+------------------------------------------------------------------+
int OnInit()
{
// 5桁業者(Digits==5 or 3)と4桁業者を自動判別してpip値を設定
if(Digits == 5 || Digits == 3)
PipValue = Point * 10; // 5桁業者: 1pip = 0.0001 = Point × 10
else
PipValue = Point; // 4桁業者: 1pip = 0.0001 = Point
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| メイン処理 — ティックが来るたびに実行される |
//+------------------------------------------------------------------+
void OnTick()
{
//--- 新しい足が確定したタイミング以外は処理をスキップ(無駄な処理を省く)
static datetime lastBarTime = 0;
if(Time[0] == lastBarTime) return;
lastBarTime = Time[0];
//--- 直前の確定バー(shift=1)のインジケーター値を取得
// BB上限バンド(UPPER: インデックス1)
double bbUpper = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_UPPER, 1);
// BB下限バンド(LOWER: インデックス2)
double bbLower = iBands(NULL, 0, BB_Period, BB_Deviation, 0, PRICE_CLOSE, MODE_LOWER, 1);
// SMA(50)の値
double ma50 = iMA(NULL, 0, MA_Period, 0, MODE_SMA, PRICE_CLOSE, 1);
// 直前確定バーの終値
double closePrice = Close[1];
//--- 現在のポジション状況を確認
bool hasBuy = HasPosition(OP_BUY); // 買いポジションがあるか
bool hasSell = HasPosition(OP_SELL); // 売りポジションがあるか
//--- 買いエントリー判定
// 条件1: 終値がBB下限バンドを下回っている(バンドアウト)
// 条件2: 終値がSMA(50)より上にある(上昇トレンド中)
// 条件3: 現在ポジションなし(最大1件制限)
if(!hasBuy && !hasSell && closePrice < bbLower && closePrice > ma50)
{
double askPrice = Ask; // 買いはAsk価格で発注
double sl = askPrice - StopLossPips * PipValue; // 損切り価格
double tp = askPrice + TakeProfitPips * PipValue; // 利確価格
int ticket = OrderSend(
Symbol(), // 現在のチャートの通貨ペア
OP_BUY, // 買い注文
LotSize, // ロットサイズ
askPrice, // 発注価格
Slippage, // スリッページ許容幅
sl, // 損切り価格
tp, // 利確価格
"BB+MA Buy", // コメント(MT4の取引履歴に表示される)
MagicNumber, // マジックナンバー
0, // 有効期限なし
clrBlue // チャート上の矢印の色
);
if(ticket < 0)
Print("買い注文エラー: ", GetLastError()); // エラーログを出力
}
//--- 売りエントリー判定
// 条件1: 終値がBB上限バンドを上回っている(バンドアウト)
// 条件2: 終値がSMA(50)より下にある(下降トレンド中)
// 条件3: 現在ポジションなし(最大1件制限)
if(!hasBuy && !hasSell && closePrice > bbUpper && closePrice < ma50)
{
double bidPrice = Bid; // 売りはBid価格で発注
double sl = bidPrice + StopLossPips * PipValue; // 損切り価格
double tp = bidPrice - TakeProfitPips * PipValue; // 利確価格
int ticket = OrderSend(
Symbol(),
OP_SELL, // 売り注文
LotSize,
bidPrice,
Slippage,
sl,
tp,
"BB+MA Sell",
MagicNumber,
0,
clrRed // チャート上の矢印の色
);
if(ticket < 0)
Print("売り注文エラー: ", GetLastError());
}
}
//+------------------------------------------------------------------+
//| ポジション有無を確認するヘルパー関数 |
//| 引数 orderType: OP_BUY または OP_SELL |
//| 戻り値: このEAが保有する指定タイプのポジションがある場合 true |
//+------------------------------------------------------------------+
bool HasPosition(int orderType)
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
// マジックナンバーと通貨ペアでこのEAのポジションだけを絞り込む
if(OrderMagicNumber() == MagicNumber &&
OrderSymbol() == Symbol() &&
OrderType() == orderType)
{
return(true); // 該当するポジションが存在する
}
}
}
return(false); // ポジションなし
}
//+------------------------------------------------------------------+
//| このEAが保有する全ポジションを閉じるヘルパー関数 |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
for(int i = OrdersTotal() - 1; i >= 0; i--)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderMagicNumber() != MagicNumber || OrderSymbol() != Symbol())
continue; // このEAのポジションでなければスキップ
double closePrice;
if(OrderType() == OP_BUY)
closePrice = Bid; // 買いポジションはBidで決済
else if(OrderType() == OP_SELL)
closePrice = Ask; // 売りポジションはAskで決済
else
continue; // 成行注文以外(指値・逆指値)はスキップ
bool result = OrderClose(
OrderTicket(), // 決済するオーダーのチケット番号
OrderLots(), // 全ロットを決済
closePrice, // 決済価格
Slippage // スリッページ許容幅
);
if(!result)
Print("決済エラー: ", GetLastError());
}
}
}
⚠️ WARNING
コード内の
PipValue計算(5桁業者判別)は自動で行われますが、念のため自分が使っているMT4のチャートでUSDJPYの価格表示桁数を確認してください。「1ドル = 155.XXX」のように小数点3桁なら5桁業者、「155.XX」のように小数点2桁なら4桁業者です。この判定が合っていないと損切り・利確の幅が10倍ズレます。
💡 INFO
Time[0] == lastBarTimeの判定は「足の確定タイミングだけで処理する」ためのコードです。これがないと1分足で1分に何十回もシグナルチェックが走り、パフォーマンスに影響します。確定バー(shift=1)でシグナルを判定するこのパターンは、MT4のEA開発で頻出する書き方です。
バックテストしてみよう
EAができたら、MT4のストラテジーテスターで動かしてみましょう。リアル口座ではなく、必ずデモ口座かストラテジーテスターで。
USDJPY・1時間足・2024年通年で試すと、こんな結果になります(参考値)。
| 項目 | 値 |
|---|---|
| PF | 1.05 |
| 勝率 | 43% |
| 最大ドローダウン | 18.7% |
| 取引回数 | 54回 |
PF 1.05。ぎりぎりプラス。 正直、微妙ですよね。
でもこれでいいんです。勝率43%でもPFがプラスなのは、利確(80pips)が損切り(40pips)の2倍に設定されているから。「負け回数が多くても、勝ちが大きければトータルプラス」という構造は機能しています。
問題はドローダウン18.7%。PF 1.05でこのリスクは割に合いません。ここから条件を足したり、パラメータを変えたりして改善していくのがEA開発の醍醐味です。
改善のアイデアもAIに聞けます。バックテスト結果を貼り付けて「どこを改善すべき?」と聞くだけでOKです。
ここまで読んで実際に手を動かすと、コード生成そのものよりも「エラー修正」「最終調整」「MT4/MT5への反映」で時間がかかるケースが多いです。
本サイトは理解と判断のための知識を提供し、実務を最短化する部分は専用プロンプトを道具として使う、という分担が現実的です。
次のステップ:中級編へ
改善を繰り返すのも大事ですが、もう一つ大きなステップアップがあります。
今回は「自分で理解しているインジ」を使いました。でも、自分では仕組みを説明できないインジケーターでもEA化できるとしたら?
→ 【中級編】説明できないインジでもEA化できる — Pine ScriptをAIに丸投げする方法
さらに効率よく、高精度なEAを完成させたい方へ
複数のインジケータを組み合わせた時のロジックの構築方法を含めた、AIによるEA作成の精度を高める専用プロンプトをダウンロードできます。
随時アップデートも行なっています。最速で始めたい方はこちらからプロンプトを受け取ってください。
関連記事
- AIで自分だけの最強EAをつくろう — EA開発の全体像。まだ読んでいない方はこちらから
- 【中級編】説明できないインジでもEA化できる — この記事の次のステップ。Pine Scriptを丸投げする方法
- インジケーターをAIに伝わる売買条件に変換する技術 — 売買条件の言語化をさらに深掘り
- MT4ストラテジーテスターの使い方完全ガイド — バックテストの正確な読み方と、よくある落とし穴
📢 CTA
バックテスト中に「このパラメーターを変えたらどう変わるか」を視覚的に確認したい場合、TradingViewのストラテジー機能が役立ちます。 TradingViewで無料バックテストを試す(PR)
この記事で使ったツール
- TradingView — ボリンジャーバンドとSMA(50)の確認に使用。無料プランでも主要インジケーターは利用可能
- MT4(MetaTrader4) — EAを動かすためのプラットフォーム。デモ口座は各MT4対応業者の公式サイトから無料開設可能
- ChatGPT / Claude — MQL4コードの生成に使用。どちらも無料プランで今回のコード生成は可能
本記事で紹介するEA・手法は教育目的で作成されたものです。実際の取引で利益を保証するものではありません。EAの運用は必ずデモ口座で十分にテストした上で、自己責任で行ってください。FX取引にはリスクが伴います。
次のステップ
まずデモで動作確認 → OKなら本番運用、が安全です。
デモ口座でEAを回す手順関連記事
TradingViewストラテジーテスターの使い方 — AI活用バックテスト
MT4より手軽にバックテストできるTradingViewのストラテジーテスターの使い方を解説。AIにPine Scriptを書かせて結果を確認するまでの手順を紹介。
TradingViewのアラート機能をEAの代わりに使う方法
EAを作らなくてもTradingViewのアラート+Webhookで半自動売買が実現できます。設定手順とEAとの使い分けを具体的に解説。
TradingViewの無料 vs 有料、EA開発に必要なプランはどれ?
EA開発のワークフロー別に、TradingViewの各プランで何ができるかを具体的に解説。アイデア出し・バックテスト・アラート連携など段階ごとに必要なプランを明確化。
複数条件を組み合わせたEAの作り方 — RSI+MACD+移動平均線の実例
単一インジのEAからステップアップ。AND/OR結合の考え方と、RSI・MACD・SMA200を組み合わせた実例プロンプト・バックテスト比較を解説します。
