既刊のMTFトレンドパネルインジケーターの記事は、
上位足の状態を「上昇」「下降」「レンジ」の3状態で、
文字と色のパネルに表示するだけの、裁量トレード向けインジケーターでした。
この記事では、同じ3状態判定ロジックを環境フィルターとして使い、
上位足のトレンドと現在足のエントリー方向が一致したときだけ発注する、
EAの作り方を解説します。
・既刊インジケーターの判定ロジックをEAの環境フィルターに転用する考え方
・上位足の3状態判定と現在足のMAクロスを組み合わせる設計
・損切り必須・ポジション重複防止の書き方
・実際に動くEAのコード全体
設計思想: なぜ上位足と現在足の一致を条件にするか
まず、一致を条件にする理由を整理します。
既刊インジケーターとの関係
既刊のMTFトレンドパネルは、
上位足が今どの状態かを「見て気づく」ための表示専用インジケーターでした。
本記事のEAは、同じ判定関数をそのまま`OnTick()`内に移し、
パネル表示の代わりに発注の可否判定に使います。
上位足だけ、現在足だけでは逆行しやすい
現在足の移動平均クロスだけでエントリーすると、
上位足全体では下降トレンドなのに、
一時的な戻りに逆らって買ってしまう場面が起こります。
・上位足が『レンジ』と判定された場合は、どちらの方向にも一致しないため発注を見送る
・上位足のトレンドに逆らわないことで、ダマシを減らす設計にしている
このEAの位置づけ(環境認識×EA)
既刊のADXレンジ判定EA・ボラティリティフィルターEA等と同じ、
環境認識を発注条件に組み込む系統のEAです。
上位足の状態判定(3状態)
判定の土台になる、上位足の3状態判定ロジックを確認します。
iMA()のシグネチャ(既刊記事からの再掲)
double iMA( string symbol, //通貨ペア(NULLで現在の通貨ペア) int timeframe, //時間足(0で現在の時間足) int ma_period, //MAの平均期間 int ma_shift, //MAシフト int ma_method, //平均化メソッド(MODE_SMA等) int applied_price,//適用価格(PRICE_CLOSE等) int shift //何本前の値を取得するか );
既刊記事で検証済みのシグネチャを、
そのまま使用します。
上昇/下降/レンジの判定関数
int GetHigherTrendState()
{
double fastMA = iMA(_Symbol, InpHigherTimeframe, InpFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double slowMA = iMA(_Symbol, InpHigherTimeframe, InpSlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double diffPoints = (fastMA - slowMA) / _Point;
if(diffPoints > InpRangeThresholdPoints)
return(1);
if(diffPoints < -InpRangeThresholdPoints)
return(-1);
return(0);
}
戻り値は、1が上昇、-1が下降、0がレンジです。
既刊インジケーターの表示ロジックと、計算部分は全く同じです。
ヒステリシス(閾値の余白)を持たせる理由
短期MAと長期MAの差がわずかな場合に上昇・下降を断定すると、
方向感のない相場を誤ってトレンドと判定してしまいます。
`InpRangeThresholdPoints`で余白を持たせることで、
この誤判定とチャタリングを防ぎます。
現在足のエントリートリガー(MAクロス)
発注の引き金になる、現在足のクロス判定を確認します。
確定足(1本前)でのクロス判定
int GetEntryTrigger()
{
double fastPrev = iMA(_Symbol, 0, InpEntryFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double slowPrev = iMA(_Symbol, 0, InpEntrySlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double fastPrev2 = iMA(_Symbol, 0, InpEntryFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
double slowPrev2 = iMA(_Symbol, 0, InpEntrySlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
if(fastPrev2 <= slowPrev2 && fastPrev > slowPrev)
return(1);
if(fastPrev2 >= slowPrev2 && fastPrev < slowPrev)
return(-1);
return(0);
}
現在足の短期MAが長期MAを上抜け・下抜けした瞬間だけを検知します。
「一致」条件の組み方
bool BuySignal()
{
return(GetEntryTrigger() == 1 && GetHigherTrendState() == 1);
}
bool SellSignal()
{
return(GetEntryTrigger() == -1 && GetHigherTrendState() == -1);
}
現在足のクロス方向と、上位足の3状態判定が同じ方向のときだけ、
trueを返します。
ポジション重複を防ぐチェック
bool HasOpenPosition()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) &&
OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagic)
return(true);
}
return(false);
}
同じ通貨ペア・同じマジックナンバーのポジションがあれば、
新規エントリーをスキップします。
損切り・利確の設定
発注時には必ず損切り・利確を指定します。
固定pipsでの指定
このEAはトレーリングストップを扱わないため、
既刊記事群と同じく発注時点の固定pipsで損切り・利確を設定します。
幅の目安
・固定pipsの幅は通貨ペア・時間足で最適値が異なる
・既刊のATRインジケーター記事の値を参考に調整するとよい
実際に動くコード全体
上位足と現在足のトレンド方向が一致したときだけエントリーする、
実際にMetaEditorでコンパイルできるEAです。
//+------------------------------------------------------------------+
//| MtfTrendAgreementEA.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 int InpHigherTimeframe = PERIOD_H4; //上位足
input int InpFastPeriod = 20; //上位足の短期MA期間
input int InpSlowPeriod = 50; //上位足の長期MA期間
input double InpRangeThresholdPoints = 50; //レンジ判定の余白(point)
input int InpEntryFastPeriod = 5; //現在足の短期MA期間
input int InpEntrySlowPeriod = 20; //現在足の長期MA期間
input double InpLots = 0.1; //発注ロット数
input int InpStopLossPips = 300; //損切り(pips)
input int InpTakeProfitPips = 600; //利確(pips)
input int InpMagic = 20261024; //マジックナンバー
int OnInit()
{
if(InpHigherTimeframe < _Period)
{
Alert("上位足は現在のチャートの時間足以上を指定してください");
return(INIT_PARAMETERS_INCORRECT);
}
return(INIT_SUCCEEDED);
}
int GetHigherTrendState()
{
double fastMA = iMA(_Symbol, InpHigherTimeframe, InpFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double slowMA = iMA(_Symbol, InpHigherTimeframe, InpSlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 0);
double diffPoints = (fastMA - slowMA) / _Point;
if(diffPoints > InpRangeThresholdPoints)
return(1);
if(diffPoints < -InpRangeThresholdPoints)
return(-1);
return(0);
}
int GetEntryTrigger()
{
double fastPrev = iMA(_Symbol, 0, InpEntryFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double slowPrev = iMA(_Symbol, 0, InpEntrySlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 1);
double fastPrev2 = iMA(_Symbol, 0, InpEntryFastPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
double slowPrev2 = iMA(_Symbol, 0, InpEntrySlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 2);
if(fastPrev2 <= slowPrev2 && fastPrev > slowPrev)
return(1);
if(fastPrev2 >= slowPrev2 && fastPrev < slowPrev)
return(-1);
return(0);
}
bool BuySignal()
{
return(GetEntryTrigger() == 1 && GetHigherTrendState() == 1);
}
bool SellSignal()
{
return(GetEntryTrigger() == -1 && GetHigherTrendState() == -1);
}
bool HasOpenPosition()
{
for(int i = 0; i < OrdersTotal(); i++)
{
if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES) &&
OrderSymbol() == _Symbol && OrderMagicNumber() == InpMagic)
return(true);
}
return(false);
}
void OnTick()
{
if(HasOpenPosition())
return;
double point = _Point;
if(_Digits == 3 || _Digits == 5)
point *= 10;
if(BuySignal())
{
double sl = Ask - InpStopLossPips * point;
double tp = Ask + InpTakeProfitPips * point;
int ticket = OrderSend(_Symbol, OP_BUY, InpLots, Ask, 3, sl, tp,
"MtfAgreement", InpMagic, 0, clrBlue);
if(ticket < 0)
Print("買い発注に失敗しました。エラーコード: ", GetLastError());
}
else if(SellSignal())
{
double sl = Bid + InpStopLossPips * point;
double tp = Bid - InpTakeProfitPips * point;
int ticket = OrderSend(_Symbol, OP_SELL, InpLots, Bid, 3, sl, tp,
"MtfAgreement", InpMagic, 0, clrRed);
if(ticket < 0)
Print("売り発注に失敗しました。エラーコード: ", GetLastError());
}
}
MetaEditorでのコンパイル・実行手順
- MetaEditorで新規Expert Advisor「MtfTrendAgreementEA」を作成し、上のコードを貼り付ける
- F7キーでコンパイルし、「0 error(s), 0 warning(s)」になることを確認する
- 1時間足以下のチャートにドラッグ&ドロップで適用する
- ストラテジーテスターで、上位足と現在足の方向が一致した場面だけエントリーしていることを確認する
よくあるエラーと注意点
実際に運用する前に確認しておきたい点をまとめます。
上位足を現在足より小さく指定すると初期化に失敗する
・既刊インジケーターと同じく、下位足を指定するとOnInit()がエラーで止まる
・あくまで『今見ているチャートより大きい時間足』を指定する前提の設計
一致条件が厳しくエントリーが少ない
上位足のレンジ判定の頻度が高い相場では、
一致条件を満たす場面自体が少なくなります。
`InpRangeThresholdPoints`を小さくすると、
レンジと判定される範囲が狭まり、エントリー頻度が増えます。
バックテストで上位足データが不足する
上位足の期間が長い履歴データを必要とするため、
ヒストリーセンターで上位足のデータを十分な期間ダウンロードしてから、
バックテストを実行してください。
MQL4とMQL5の違い
MTF環境フィルターの考え方を、MQL5に移植する場合の違いを確認します。
MQL4は値を直接返す方式
MQL4の`iMA()`は、timeframeに上位足の定数を渡すだけで、
直接その時間足の値を返します。
MQL5はハンドル方式に変わる
MQL5では、時間足ごとにハンドルを作成し、
`CopyBuffer`で値を取得する設計に変わります。
既刊copybuffer.mdのハンドル方式を応用すれば移植できます。
一致判定の考え方はそのまま応用できる
「上位足の状態と現在足のシグナルを両方確認してから発注する」
という設計自体は、MQL5に移植する場合でもそのまま応用できます。
よくある質問
MTFトレンド一致EAについて、よくある疑問に回答します。
・既刊インジケーターと併用すれば、一致判定の根拠を目視でも確認できる
・上位足の期間(短期MA・長期MA)はバックテストで調整する
・レンジ判定が多すぎる場合は閾値を見直す
既刊MTFトレンドパネルと両方入れるべきですか?
必須ではありません。
このEAは判定ロジックを内部に持っているため単独で動作しますが、
目視で経過を確認したい場合は既刊インジケーターを併用してください。
一致条件を外して裁量判断にすることはできますか?
できます。
`BuySignal()`・`SellSignal()`から、
`GetHigherTrendState()`の条件を外せば、
現在足だけのシンプルなMAクロスEAに戻せます。
3つ以上の時間足の一致にできますか?
できます。
`GetHigherTrendState()`と同じ関数を時間足違いで複数用意し、
`BuySignal()`の条件にすべて`&&`で追加すれば、
3つ以上の時間足が一致したときだけ発注する設計に拡張できます。
ただし条件が厳しくなるほどエントリー頻度は下がります。
【MQL4】上位足と現在足のトレンド方向が一致したときだけエントリーするEAの作り方(mtf-trend-panel-indicator-mt4.mdの発展形):まとめ
既刊のMTFトレンドパネルインジケーターは、
上位足の状態を知らせるだけの表示専用の設計でした。
同じ3状態判定ロジックを環境フィルターとして使い、
上位足と現在足のトレンド方向が一致したときだけ発注する設計にすることで、
上位足に逆らうエントリーを減らせます。
コメント