RSIが70や30を超えたから逆張りで入ったのに、

強いトレンドにそのまま飲まれて損切りになった、

という経験はないでしょうか。

RSIやCCIのような逆張り系の指標は、「買われすぎ・売られすぎ」

を判定する指標であって、「今がトレンドかレンジか」までは判定していません。

ADXは逆に、方向ではなく、トレンドの「強さ」だけを数値で返す指標です。

この記事では、ADXが低い、つまりレンジ相場だと判定したときだけ、

RSIの逆張りシグナルを有効にするEAの作り方を解説します。

この記事で分かること
・ADXでトレンドかレンジかを判定する考え方
・iADXとiRSIを組み合わせる作り方
・既刊の逆張りEAとの設計上の違い
・MQL4とMQL5でiADXの扱いがどう変わるか

なぜ逆張りEAにADXフィルターが必要なのか

まず、このフィルターが必要になる理由を確認します。

強いトレンド中はRSIが伸び続ける

トレンドが強いときは、RSIが70を超えたまま下がらずに、

価格がさらに上昇を続けることがあります。

逆張りはレンジ相場向けの手法

逆張りという手法そのものが、価格が一定の範囲を往復するレンジ相場を前提にしているため、

強いトレンドの最中に使うと手法とのミスマッチが起きます。

既刊のADX系記事との関係

既刊のadx-strength-indicator.mdでは、

ADXの値をインジケーターとして表示するところまで扱いました。

本記事では同じ判定ロジックを、エントリーの許可・禁止を決めるEAの関数として発展させます。

ADXの値の見方をおさらいする

ADXフィルターを作る前に、関数の仕様を確認します。

iADX関数の書式

double iADX(
   string symbol,       //通貨ペア(NULLで現在のチャートの通貨ペア)
   int    timeframe,    //時間足(0で現在のチャートの時間足)
   int    period,       //ADXの計算期間
   int    applied_price, //価格の種類(PRICE_CLOSE等)
   int    mode,         //取得するライン(MODE_MAIN/MODE_PLUSDI/MODE_MINUSDI)
   int    shift         //バーのシフト(0が現在のバー)
   );

mode引数には3種類の定数を渡せますが、本記事で使うのは「強さ」

だけを表すMODE_MAIN(値は0)です。

+DIと-DIは今回使わない

用語補足
・+DIと-DIは上昇と下降の圧力を示す
・MODE_MAIN(ADX本体)は強さだけを示す
・レンジ判定にはMODE_MAINが適している

絶対値でなく閾値で判定する

ADXの値そのものに絶対的な正解の基準はありませんが、

一般に20〜25を下回るとトレンドが弱い、

つまりレンジ気味とされます。

通貨ペアや時間足によって適切な値は変わるため、

本記事ではこの基準値を入力パラメーターとして外出しします。

既刊の逆張りEAとの設計上の違い

このEAが既刊記事と何が違うのかを明確にします。

cci-reversal-ea.mdとの違い

既刊のCCI逆張りEAは、CCIの水準到達と戻りだけでエントリーを判定していましたが、

相場がトレンド中かレンジ中かは判定していませんでした。

効率比インジケーターとの違い

既刊の効率比(Efficiency Ratio)インジケーターも、

トレンド/レンジを判定する点では似ていますが、計算方法が異なり、

本記事はADXという定番指標で判定する点が違いです。

本記事ならではの差別化ポイント

RSIという逆張り指標と、ADXという強さの指標を役割分担させることで、

「逆張りすべきでない場面」を自動で避けられるようにしています。

EA全体の設計

実際にフィルター関数とエントリーロジックを組み立てます。

IsRangeMarket関数として切り出す

bool IsRangeMarket()
  {
   double adx = iADX(_Symbol, PERIOD_CURRENT, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 0);
   return(adx < ADXRangeMax);
  }

ADXの値がADXRangeMax未満であれば、レンジ相場だと判定してtrueを返す、

という単純な関数にします。

RSIの水準到達でシグナルを出す

double rsi = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE, 0);

RSIがRSIOversold以下なら買い、RSIOverbought以上なら売りという、

一般的な逆張り条件を採用します。

ポジション重複防止と損切りの必須設定

注意
・OrderMagicNumberで自分の注文だけ数える
・OrderSendのslは必ず0以外を指定する
・損切り無しだと1回の大負けで帳消しになる

実際に動くコード全体

ここまでの要素をまとめた、実際に動くEAです。

//+------------------------------------------------------------------+
//|                                   ADXRangeReversalEA.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    ADXPeriod      = 14;
input double ADXRangeMax    = 20.0;   //この値未満ならレンジ相場と判定
input int    RSIPeriod      = 14;
input double RSIOverbought  = 70.0;
input double RSIOversold    = 30.0;
input double FixedLots      = 0.1;
input int    StopLossPips   = 300;
input int    TakeProfitPips = 300;
input int    MagicNumber    = 20261006;

bool IsRangeMarket()
  {
   double adx = iADX(_Symbol, PERIOD_CURRENT, ADXPeriod, PRICE_CLOSE, MODE_MAIN, 0);
   return(adx < ADXRangeMax);
  }

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 OpenOrder(int type)
  {
   double price = (type == OP_BUY) ? Ask : Bid;
   double sl = (type == OP_BUY) ? price - StopLossPips * Point : price + StopLossPips * Point;
   double tp = (type == OP_BUY) ? price + TakeProfitPips * Point : price - TakeProfitPips * Point;

   int ticket = OrderSend(_Symbol, type, FixedLots, price, 3, sl, tp,
                          "ADXRangeReversalEA", MagicNumber, 0,
                          (type == OP_BUY) ? clrBlue : clrRed);

   if(ticket < 0)
      Print("OrderSendに失敗しました。エラーコード=", GetLastError());
  }

void OnTick()
  {
   if(!IsTradeAllowed())
      return;

   if(HasOpenPosition())
      return;

   if(!IsRangeMarket())
      return;

   double rsi = iRSI(_Symbol, PERIOD_CURRENT, RSIPeriod, PRICE_CLOSE, 0);

   if(rsi <= RSIOversold)
      OpenOrder(OP_BUY);
   else if(rsi >= RSIOverbought)
      OpenOrder(OP_SELL);
  }

MetaEditorでのコンパイル・実行手順

実際にMT4で動かすまでの手順を確認します。

  1. MetaEditorで新規EA「ADXRangeReversalEA」を作成し、上のコードを貼り付けてコンパイルする
  2. エラー・警告が0件であることを確認する
  3. ストラテジーテスターでADXRangeMaxを80程度(フィルターほぼ無効)にして一度バックテストする
  4. 次にADXRangeMaxを20程度に戻し、同じ期間で再度バックテストする
  5. 両者の取引回数・勝率・最大ドローダウンを比較し、フィルターの効果を確認する

よくあるエラーと注意点

実装でつまずきやすいポイントをまとめます。

mode引数を間違えてしまう

modeに1や2を渡すと、「強さ」ではなく「方向の圧力」を取得してしまい、

レンジ判定の条件が意図通りに動きません。

ADXRangeMaxを厳しくしすぎる

ADXRangeMaxを極端に小さくすると、レンジと判定される場面がほとんど無くなり、

バックテストで取引回数が0に近くなることがあります。

MQL4とMQL5の違い

このコードはMQL4のiADXを使った書き方です。

MQL5ではiADXはインジケーターハンドルを返す方式に変わり、

CopyBufferに渡して値を取得する設計に変更する必要があります。

よくある質問

ADXレンジフィルターについて、よくある疑問に回答します。

ADXRangeMaxはいくつに設定すればいいですか?

一般的には20〜25が目安とされますが、通貨ペアや時間足によって適切な値は変わるため、

バックテストで値を変えながら取引回数と勝率のバランスを確認することをおすすめします。

順張りEAにもADXフィルターは使えますか?

使えます。

IsRangeMarket()の判定を反転させ、

ADXが高いときだけエントリーを許可すれば、

順張りEAのトレンドフィルターとして転用できます。

RSI以外の逆張り指標と組み合わせてもいいですか?

問題ありません。

本記事のIsRangeMarket()は、

RSIの判定部分と完全に分離した関数になっているため、

CCIやDeMarkerなど他の指標にもそのまま組み合わせられます。

【MQL4】ADXでトレンドの強さを判定し、レンジ相場のときだけ逆張りエントリーするEAの作り方について解説してみた:まとめ

ADXは方向ではなくトレンドの「強さ」だけを示す指標のため、

レンジ相場だと判定してからRSIの逆張りシグナルを有効にするフィルターとして活用できます。

IsRangeMarket()関数として判定ロジックを切り出しておくことで、

既存の逆張りEAにもOnTickの冒頭に1行追加するだけで組み込める設計にしています。

関連記事