1日の損失額だけを監視するEAを作っていても、1日ごとの損失は上限内に収まっているのに、
その負けが数日続いて資産が気づかないうちに大きく減っていた、
という経験はないでしょうか。
これは「1日単位」の監視だけでは、
複数日にわたって積み重なる下落(ドローダウン)を、
捉えられないために起こります。
この記事では、資産の最高値(ピーク)からどれだけ下落したかを%で常に監視し、
一定の割合を超えたら新規エントリーだけを自動で止めるEAの作り方を解説します。
・ドローダウンを「ピーク比の%」で考える理由
・GlobalVariableでピーク資産を記憶する設計
・既刊の1日単位の損失上限EAとの違い
・端末再起動後もピークを引き継ぐ注意点
なぜ「1日の損失額」だけでは資産を守れないのか
まず、このEAが解決する問題を確認します。
1日単位の監視は「日をまたぐ連敗」に弱い
1日の損失が上限未満でも、その負けが3日、5日と連続すれば、
資産全体は着実に減っていきます。
既刊daily-loss-limit-close-all-ea-mt4.mdとの違い
既刊記事は「1日の含み損の合計額」が固定の金額を超えたら全決済する設計でしたが、
本記事は「資産の最高値からの下落率」という、日をまたいで累積する指標を使います。
本記事は強制決済しない設計である
既刊記事とは異なり、本記事は既存ポジションを強制的に決済しません。
新規エントリーだけを止め、今あるポジションの管理はトレーダー自身の判断に委ねる設計です。
ドローダウンを「ピーク比の%」で考える
ドローダウンの考え方を確認します。
固定金額ではなく比率で見る理由
・ドローダウン=ピーク資産からの下落額
・ピーク比の%なら口座残高が増減しても
・同じ設定を使い回せる
ピーク資産はAccountEquity()の最大値
ピーク資産は、口座残高(Balance)ではなく、
未決済の損益を含む有効証拠金(Equity)の、
これまでの最大値として追跡します。
ドローダウン率の計算式
ドローダウン率(%) = (ピーク資産 - 現在のEquity) / ピーク資産 * 100
この値が入力パラメーターの上限を超えたときに、新規エントリーを止める判定を行います。
GlobalVariableでピーク資産を記憶する設計
端末再起動後もピークを引き継ぐための設計を確認します。
なぜ変数ではなくGlobalVariableを使うのか
通常の変数はEAの再起動やMT4の終了でリセットされますが、
GlobalVariableは端末を閉じても一定期間値が保持されます。
GlobalVariableSet/GlobalVariableGetの書式
double GlobalVariableSet(string name, double value); double GlobalVariableGet(string name); bool GlobalVariableCheck(string name);
GlobalVariableCheckで変数が既に存在するか確認し、
無ければAccountEquity()の現在値で初期化します。
変数名の衝突に注意する
・GlobalVariableは端末内の全EAで共有される
・名前にSymbol()等を含めて他EAと衝突を避ける
・既刊globalvariableset-get-mt4.mdも参照
EA全体の設計
実際にピーク追跡とエントリー停止判定を組み立てます。
OnInitでピーク変数を準備する
gvKey = "DD_Peak_" + Symbol(); if(!GlobalVariableCheck(gvKey)) GlobalVariableSet(gvKey, AccountEquity());
初回起動時だけ、現在のEquityをピークの初期値として記録します。
OnTickでピークの更新と判定を行う
double peak = GlobalVariableGet(gvKey);
double equity = AccountEquity();
if(equity > peak)
{
peak = equity;
GlobalVariableSet(gvKey, peak);
}
double ddPercent = (peak - equity) / peak * 100.0;
Equityがピークを更新したら、その都度GlobalVariableも書き換えます。
新規エントリーだけを止める
ddPercentが入力パラメーターの上限以上なら、Comment()で状態を表示し、
エントリー処理に進まずreturnします。
既存ポジションにはいっさい触れません。
実際に動くコード全体
ここまでの要素をまとめた、実際に動くEAです。
//+------------------------------------------------------------------+
//| DrawdownLimitStopEA.mq4 |
//| Copyright 2026, FX-EA System Project Creator |
//| https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, FX-EA System Project Creator"
#property link "https://creator.fx-ea-system-project.com/"
#property version "1.00"
#property strict
input double DrawdownLimitPercent = 20.0; //ピーク比でこの%を超えたら新規停止
input int FastMAPeriod = 5;
input int SlowMAPeriod = 20;
input double FixedLots = 0.1;
input int StopLossPips = 300;
input int MagicNumber = 20261006;
string gvKey;
int OnInit()
{
gvKey = "DD_Peak_" + Symbol();
if(!GlobalVariableCheck(gvKey))
GlobalVariableSet(gvKey, AccountEquity());
return(INIT_SUCCEEDED);
}
double UpdatePeakAndGetDrawdown()
{
double peak = GlobalVariableGet(gvKey);
double equity = AccountEquity();
if(equity > peak)
{
peak = equity;
GlobalVariableSet(gvKey, peak);
}
if(peak <= 0)
return(0);
return((peak - equity) / peak * 100.0);
}
bool HasOpenPosition()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
{
if(OrderSymbol() == _Symbol && OrderMagicNumber() == MagicNumber)
return(true);
}
}
return(false);
}
void OnTick()
{
double ddPercent = UpdatePeakAndGetDrawdown();
if(ddPercent >= DrawdownLimitPercent)
{
Comment("ドローダウン上限に到達: ", DoubleToString(ddPercent, 1),
"% (新規エントリー停止中、既存ポジションは対象外)");
return;
}
Comment("現在のドローダウン: ", DoubleToString(ddPercent, 1), "%");
if(HasOpenPosition())
return;
double fastMA = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double slowMA = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double fastMAPrev = iMA(_Symbol, PERIOD_CURRENT, FastMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double slowMAPrev = iMA(_Symbol, PERIOD_CURRENT, SlowMAPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double sl = 0;
if(fastMAPrev <= slowMAPrev && fastMA > slowMA)
{
sl = Ask - StopLossPips * Point;
OrderSend(_Symbol, OP_BUY, FixedLots, Ask, 3, sl, 0, "DrawdownLimitStopEA", MagicNumber, 0, clrBlue);
}
else if(fastMAPrev >= slowMAPrev && fastMA < slowMA)
{
sl = Bid + StopLossPips * Point;
OrderSend(_Symbol, OP_SELL, FixedLots, Bid, 3, sl, 0, "DrawdownLimitStopEA", MagicNumber, 0, clrRed);
}
}
MetaEditorでのコンパイル・実行手順
実際にMT4で動かすまでの手順を確認します。
- MetaEditorで新規EA「DrawdownLimitStopEA」を作成し、上のコードを貼り付けてコンパイルする
- エラー・警告が0件であることを確認する
- デモ口座でチャートに適用し、コメント欄にドローダウン率が表示されることを確認する
- DrawdownLimitPercentを一時的に低い値(例: 1.0)にして、エントリー停止が実際に発生することを確認する
- 確認後は想定する運用値(例: 20.0)に戻す
よくあるエラーと注意点
実装でつまずきやすいポイントをまとめます。
ピークの初期化タイミングを誤解する
EAを後から取り付けた場合、ピークはその時点のEquityから始まります。
それより前に発生していた下落は、このEAのドローダウン率に反映されません。
バックテストと実運用でGlobalVariableの挙動が違う
ストラテジーテスター内のGlobalVariableは実運用の値と分離されているため、
バックテストのたびにピークがリセットされた状態から始まります。
MQL4とMQL5の違い
このコードはMQL4のAccountEquity()を使った書き方です。
MQL5ではAccountInfoDouble(ACCOUNT_EQUITY)という、
引数指定の関数に置き換える必要があります。
よくある質問
ドローダウン制限EAについて、よくある疑問に回答します。
既存ポジションも強制的に決済すべきですか?
本記事ではあえて強制決済しない設計にしています。
既存ポジションの損切り・保有判断は手法ごとに異なるため、
新規停止と決済は別の機能として分けるべきだと考えたためです。
必要であれば、既刊の1日の損失上限EAの、
全決済処理を組み合わせることもできます。
DrawdownLimitPercentはいくつに設定すればいいですか?
一般的には10〜25%程度が目安とされますが、
手法の最大想定ドローダウンや資金の余裕度によって、
適切な値は変わります。
バックテストで自分の手法の最大ドローダウンを確認した上で、
その値より少し手前に設定することをおすすめします。
複数の通貨ペアで同じEAを動かす場合はどうなりますか?
本記事のgvKeyはSymbol()を含めているため、
通貨ペアごとに別のピークが記録されます。
口座全体のドローダウンを1つの基準で監視したい場合は、
gvKeyを固定文字列にして全ペア共通のピークにする必要があります。
【MQL4】資産のピーク(最高値)からの下落率でドローダウンを監視し、新規エントリーを自動停止するEAの作り方について解説してみた:まとめ
1日単位の損失額の監視だけでは、日をまたいで積み重なるドローダウンを捉えられません。
資産のピークからの下落率を%で常に監視し、
一定の割合を超えたら新規エントリーだけを自動で止める設計にすることで、
既存ポジションの判断は手法に委ねたまま、
累積的なリスクだけを機械的に制限できます。
GlobalVariableでピークを永続化しておくことで、
端末の再起動を挟んでも監視を継続できる設計にしています。
コメント