ADXの数値を見ても、

「これはトレンドなのかレンジなのか」判断に迷ったことはないでしょうか。

ADXは「強さ」は教えてくれますが、

値動きが一方向にムダなく進んでいるかどうかまでは教えてくれません。

この記事では、「効率比(Efficiency Ratio)」という考え方を使い、

値動きのムダの少なさを0〜1の数値にして、

チャート上のパネルに「トレンド相場」「レンジ相場」と表示する

MT4インジケーターの作り方を解説します。

この記事で分かること
・効率比(Efficiency Ratio)とは何を計算した数値か
・ADXだけでは判定しにくい理由
・OBJ_RECTANGLE_LABELで背景色付きパネルを作る方法
・閾値で「トレンド」「レンジ」を自動判定する設計

トレンド/レンジ判定の考え方

まず、なぜ「効率比」という別の指標を使うのか、考え方から確認します。

なぜADXだけでは判定しにくいのか

ADXは、上昇・下降どちらの方向にも、

「動きの強さ」だけを数値化する指標です。

そのため、上下に激しく振れながらも、

結果的に平均足で見ればトレンドっぽく見える相場でも、

高い値が出ることがあります。

効率比(Efficiency Ratio)の計算式

効率比は、「実際に進んだ距離」を

「動いた距離の合計」で割った比率です。

効率比 = |終値[0] - 終値[period]| ÷ Σ|終値[i] - 終値[i+1]|

分子は、期間の最初と最後を直線で結んだときの値幅です。

分母は、1本ずつの値幅をすべて足し合わせた「実際の移動距離」です。

値の読み方(1に近いほどトレンド)

一直線に進んだ相場では、

分子と分母がほぼ同じ値になり、効率比は1に近づきます。

上下に往復しながらほとんど進んでいない相場では、

分母だけが大きくなり、効率比は0に近づきます。

補足
・この考え方はJ.カウフマンが考案した『効率比』の基本式です
・移動平均線の追従速度を変えるAMA(適応型移動平均)の土台としても有名です
・本記事では平均化には使わず、判定だけに単体で利用します

効率比を計算するコード

上の考え方を、そのままMQL4の配列計算に落とし込みます。

直線的な値幅(分子)の求め方

double direction = MathAbs(Close[shift] - Close[shift + period]);

`Close[]`配列は添字0が最新の確定足(または現在バー)です。

`period`本前の終値との差の絶対値を取るだけで、分子が求まります。

実際に動いた値幅の合計(分母)の求め方

double volatility = 0.0;
for(int i = shift; i < shift + period; i++)
   volatility += MathAbs(Close[i] - Close[i + 1]);

1本ずつの値幅の絶対値を、`period`本分ループして足し合わせます。

ゼロ除算を避ける工夫

値動きが完全に停止した極端なケースでは、

分母(`volatility`)が0になることがあります。

if(volatility == 0.0)
   return(0.0);
return(direction / volatility);

0除算を避けるため、分母が0のときは効率比を0として扱います。

パネルで表示する設計

計算した効率比を、チャート上の色付きパネルに反映します。

OBJ_RECTANGLE_LABELで背景の箱を作る

ObjectCreate(0, "TRPanelBox", OBJ_RECTANGLE_LABEL, 0, 0, 0);
ObjectSetInteger(0, "TRPanelBox", OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, "TRPanelBox", OBJPROP_XDISTANCE, 10);
ObjectSetInteger(0, "TRPanelBox", OBJPROP_YDISTANCE, 20);
ObjectSetInteger(0, "TRPanelBox", OBJPROP_XSIZE, 150);
ObjectSetInteger(0, "TRPanelBox", OBJPROP_YSIZE, 26);

`OBJ_LABEL`と同じくスクリーン座標のオブジェクトなので、

`time1`・`price1`はダミーの0を渡します。

閾値で背景色を切り替える

if(er >= InpTrendThreshold)
   ObjectSetInteger(0, "TRPanelBox", OBJPROP_BGCOLOR, clrSteelBlue);
else
   ObjectSetInteger(0, "TRPanelBox", OBJPROP_BGCOLOR, clrDimGray);

効率比が入力パラメータの閾値以上ならトレンド色、

未満ならレンジ色に、背景だけを毎回塗り替えます。

実際に動くコード全体

効率比を計算し、パネルの文字と背景色を更新するカスタムインジケーターです。

//+------------------------------------------------------------------+
//|                                 TrendRangeEfficiencyPanel.mq4      |
//|                     Copyright 2026, FX-EA System Project Creator |
//|                        https://creator.fx-ea-system-project.com/ |
//+------------------------------------------------------------------+
#property strict
#property indicator_chart_window
#property indicator_buffers 0

input int    InpPeriod         = 14;
input double InpTrendThreshold = 0.30;

string PanelBox   = "TRPanelBox";
string PanelLabel = "TRPanelLabel";

int OnInit()
  {
   ObjectCreate(0, PanelBox, OBJ_RECTANGLE_LABEL, 0, 0, 0);
   ObjectSetInteger(0, PanelBox, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, PanelBox, OBJPROP_XDISTANCE, 10);
   ObjectSetInteger(0, PanelBox, OBJPROP_YDISTANCE, 20);
   ObjectSetInteger(0, PanelBox, OBJPROP_XSIZE, 150);
   ObjectSetInteger(0, PanelBox, OBJPROP_YSIZE, 26);
   ObjectSetInteger(0, PanelBox, OBJPROP_BGCOLOR, clrDimGray);
   ObjectSetInteger(0, PanelBox, OBJPROP_BACK, false);

   ObjectCreate(0, PanelLabel, OBJ_LABEL, 0, 0, 0);
   ObjectSetInteger(0, PanelLabel, OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(0, PanelLabel, OBJPROP_XDISTANCE, 18);
   ObjectSetInteger(0, PanelLabel, OBJPROP_YDISTANCE, 26);
   ObjectSetText(PanelLabel, "判定中...", 11, "Arial", clrWhite);

   return(INIT_SUCCEEDED);
  }

void OnDeinit(const int reason)
  {
   ObjectDelete(0, PanelBox);
   ObjectDelete(0, PanelLabel);
  }

double EfficiencyRatio(int period, int shift)
  {
   double direction = MathAbs(Close[shift] - Close[shift + period]);

   double volatility = 0.0;
   for(int i = shift; i < shift + period; i++)
      volatility += MathAbs(Close[i] - Close[i + 1]);

   if(volatility == 0.0)
      return(0.0);

   return(direction / volatility);
  }

int OnCalculate(const int rates_total, const int prev_calculated,
                const datetime &time[], const double &open[],
                const double &high[], const double &low[],
                const double &close[], const long &tick_volume[],
                const long &volume[], const int &spread[])
  {
   if(rates_total <= InpPeriod + 1)
      return(rates_total);

   double er = EfficiencyRatio(InpPeriod, 0);

   if(er >= InpTrendThreshold)
     {
      ObjectSetInteger(0, PanelBox, OBJPROP_BGCOLOR, clrSteelBlue);
      ObjectSetText(PanelLabel, "トレンド相場 (" + DoubleToString(er, 2) + ")", 11, "Arial", clrWhite);
     }
   else
     {
      ObjectSetInteger(0, PanelBox, OBJPROP_BGCOLOR, clrDimGray);
      ObjectSetText(PanelLabel, "レンジ相場 (" + DoubleToString(er, 2) + ")", 11, "Arial", clrWhite);
     }

   return(rates_total);
  }

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

  1. MetaEditorで新規カスタムインジケーター「TrendRangeEfficiencyPanel」を作成し、上のコードを貼り付けてコンパイルする
  2. MT4のナビゲーターからチャートへドラッグ&ドロップして適用する
  3. チャート左上に色付きパネルが表示され、「トレンド相場」または「レンジ相場」と数値が表示されることを確認する
  4. 相場が大きく動いた直後にパネルの色と数値が切り替わることを確認する

よくあるエラーと注意点

実際に使うときにつまずきやすいポイントをまとめます。

期間を短くしすぎるとノイズで頻繁に切り替わる

注意
・InpPeriodを5等に短くすると小さな値動きにも反応します
・パネルの色が数分おきに切り替わり、かえって判断しづらくなります
・まずは既定値の14前後から試し、必要に応じて調整してください

MQL4とMQL5の違い

このコードは`Close[]`配列に直接アクセスするMQL4特有の書き方です。

MQL5では`Close[]`のようなシリーズ配列は無く、

`CopyClose`で配列にコピーしてから使う設計になります。

よくある質問

効率比を使ったトレンド/レンジ判定について、よく検索される疑問に回答します。

効率比だけでエントリー判断してよいですか?

この記事の設計は、あくまで「今の相場の性質」を判定する

補助的な指標としての利用を想定しています。

エントリーの合図には、既刊のRSIやADX等のシグナル系記事と

組み合わせて使うことをおすすめします。

InpTrendThresholdの値はどう決めればよいですか?

絶対的な正解はありません。

まずは0.3前後で試し、パネルの切り替わり頻度が

多すぎる・少なすぎると感じたら、0.05刻みで調整してみてください。

なぜADXではなく効率比を使ったのですか?

ADXは「強さ」を示す指標ですが、

効率比は「ムダなく一方向に進んでいるか」を示す指標です。

視点が異なるため、既刊のADX記事とは別の切り口として扱っています。

【MQL】効率比(Efficiency Ratio)で今がトレンド相場かレンジ相場かを判定表示するインジケーター:まとめ

効率比は、値動きのムダの少なさを0〜1の数値にする、

シンプルながら実務的な判定指標です。

`OBJ_RECTANGLE_LABEL`で背景色付きのパネルを作れば、

チャートを目視するだけで、

今がトレンドかレンジかをひと目で判断できます。

関連記事