MT4でEAの状態を色分け表示する方法|VisualMode.mqh公開

MT4でEAの状態を色分け表示する方法
EAサンプル・ノウハウ

本記事では、MT4(MQL4)でEAのモードや内部状態を 背景色・縦ライン・帯表示で可視化する方法を解説します。

EA開発をしていると、こんな疑問が出てきます。

  • 今はレンジ?トレンド?
  • なぜこの場面でエントリーした?
  • モード切替はどこで起きた?

ロジックは正しく動いていても、
状態が見えないと検証効率は上がりません。

そこで本記事では、
EAのモードを背景色・縦ライン・下段帯で可視化するライブラリ VisualMode.mqh を公開します。

単なる装飾ではありません。
これは「ロジックと描画を分離する設計」の実装例です。
include して 3行追加するだけで簡単に導入できます。


なぜ状態を可視化するのか?

EAはブラックボックスになりやすいです。

・条件は満たしているはずなのに入らない
・思っていない方向にドテンした
・フィルターが効いているのか分からない

可視化を入れるだけで、

  • デバッグ速度が上がる
  • ロジック理解が深まる
  • パラメータ調整が楽になる

つまり、
開発・検証効率が劇的に上がるのです。


VisualMode.mqhの機能

MT4でEAの状態を色分け表示する方法の解説
  • ①モード変更時に背景を塗る(履歴が残る)
  • ②切替ポイントに縦ライン表示
  • ③現在モードを下段帯で常時表示
  • EA削除時に自動クリーンアップ

しかも、
EAロジックと完全分離されています。


VisualMode.mqh(公開コード)

以下が VisualMode.mqh の全コードです。

そのまま include して使える形で整形しています。

//+------------------------------------------------------------------+
//| VisualMode.mqh                                                   |
//| 公開用・最終完成版(3状態 + 可変帯長対応)                      |
//|                                                                  |
//| 対応状態:                                                        |
//|  -1 = 表示なし                                                   |
//|   0 = モードA                                                    |
//|   1 = モードB                                                    |
//|                                                                  |
//+------------------------------------------------------------------+
#property strict

//==================================================
// ■ 内部管理変数
//==================================================
int      vm_currentMode   = -1;
datetime vm_lastModeTime  = 0;

string   VM_PREFIX = "VM_";
string   VM_BAR    = "VM_MODE_BAR";

//+------------------------------------------------------------------+
//| 初期化                                                           |
//+------------------------------------------------------------------+
void VisualMode_Init(int initMode)
{
   vm_currentMode  = initMode;
   vm_lastModeTime = Time[1];
}

//+------------------------------------------------------------------+
//| 状態更新                                                         |
//+------------------------------------------------------------------+
void VisualMode_Update(int newMode,
                       color modeAColor,
                       color modeBColor)
{
   datetime nowTime = Time[1];

   // モードが変わったときだけ背景確定&縦ライン
   if(newMode != vm_currentMode)
   {
      if(vm_currentMode == 0 || vm_currentMode == 1)
      {
         VisualMode_DrawBackground(
            vm_lastModeTime,
            nowTime,
            vm_currentMode,
            modeAColor,
            modeBColor
         );
      }

      VisualMode_DrawChangeLine(newMode, modeAColor, modeBColor);

      vm_lastModeTime = nowTime;
      vm_currentMode  = newMode;
   }


   // モードが同じでも毎バー帯は更新する
   VisualMode_DrawBar(modeAColor, modeBColor);
}
//+------------------------------------------------------------------+
//| 背景描画                                                         |
//+------------------------------------------------------------------+
void VisualMode_DrawBackground(datetime fromTime,
                               datetime toTime,
                               int mode,
                               color modeAColor,
                               color modeBColor)
{
   string name = VM_PREFIX + "BG_" + IntegerToString(fromTime);

   double top    = ChartGetDouble(0, CHART_PRICE_MAX);
   double bottom = ChartGetDouble(0, CHART_PRICE_MIN);

   color bgColor = (mode == 0 ? modeAColor : modeBColor);

   ObjectCreate(0,name,OBJ_RECTANGLE,0,
                fromTime, top,
                toTime,   bottom);

   ObjectSetInteger(0,name,OBJPROP_COLOR,bgColor);
   ObjectSetInteger(0,name,OBJPROP_BACK,true);
   ObjectSetInteger(0,name,OBJPROP_FILL,true);
}

//+------------------------------------------------------------------+
//| モード切替縦ライン                                               |
//+------------------------------------------------------------------+
void VisualMode_DrawChangeLine(int mode,
                               color modeAColor,
                               color modeBColor)
{
   string name = VM_PREFIX + "LINE_" +
                 TimeToString(Time[1], TIME_DATE|TIME_MINUTES);

   if(ObjectFind(0,name) >= 0)
      return;

   ObjectCreate(0,name,OBJ_VLINE,0,Time[1],0);

   color lineColor;

   if(mode == 0)
      lineColor = modeAColor;
   else if(mode == 1)
      lineColor = modeBColor;
   else
      lineColor = clrSilver;   // ★ -1用グレー

   ObjectSetInteger(0,name,OBJPROP_COLOR,lineColor);
   ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DOT);
   ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
}

//+------------------------------------------------------------------+
//| 下段帯描画(可変長対応)                                         |
//+------------------------------------------------------------------+
void VisualMode_DrawBar(color modeAColor, color modeBColor)
{
   string name = VM_BAR;

   // 表示対象外なら削除
   if(vm_currentMode != 0 && vm_currentMode != 1)
   {
      ObjectDelete(0,name);
      return;
   }

   color barColor = (vm_currentMode == 0 ? modeAColor : modeBColor);

   double low  = WindowPriceMin();
   double high = WindowPriceMax();
   double height = (high-low) * 0.03;

   datetime left  = vm_lastModeTime;  // ★ここがポイント
   datetime right = Time[0];

   if(ObjectFind(0,name) < 0)
   {
      ObjectCreate(0,name,OBJ_RECTANGLE,0,
                   left,low,
                   right,low+height);

      ObjectSetInteger(0,name,OBJPROP_BACK,true);
   }

   ObjectSetInteger(0,name,OBJPROP_COLOR,barColor);
   ObjectMove(0,name,0,left,low);
   ObjectMove(0,name,1,right,low+height);
}
//+------------------------------------------------------------------+
//| クリーンアップ                                                   |
//+------------------------------------------------------------------+
void VisualMode_Deinit()
{
   int total = ObjectsTotal();

   for(int i=total-1; i>=0; i--)
   {
      string name = ObjectName(i);

      if(StringFind(name,VM_PREFIX) == 0)
         ObjectDelete(0,name);
   }

   ObjectDelete(0,VM_BAR);
}

使い方

① include を追加

まず、VisualMode.mqh を MQL4 / Include フォルダに保存します。

その上で、EAファイルの先頭に以下を追加します。


#include <VisualMode.mqh>

コンパイル後、MetaEditorの「詳細」タブに 'VisualMode.mqh' と表示されていれば、 正しく読み込まれています。

MQL4でmqhインクルード
※コンパイルすると、以下のように読み込まれたファイル名が表示されます。


⚠️ エラーが出る場合は、保存場所が
MQL4 / Includeになっているか確認してください。

② OnInit() で初期化

VisualMode.mqh は 3状態対応の表示ライブラリです。

  • -1 = 表示なし(中立)
  • 0 = モードA
  • 1 = モードB

// 初期状態(例:中立)
VisualMode_Init(-1);

ここで指定する値は「表示の初期状態」です。
EA内部のロジック状態とは独立しています。

例えばEA側が

  • 1 = アップトレンド
  • 2 = ダウントレンド
  • 0 = どちらでもない

のような複数状態を持っていても、
表示時に -1 / 0 / 1 に変換して渡せば問題ありません。

③ モード変更時に Update を呼ぶ

状態が切り替わったタイミングで呼び出します。

第2引数は「0 のときの色」、
第3引数は「1 のときの色」です。


// 例:モードA=青、モードB=赤
int visualState = 0; // -1 / 0 / 1

VisualMode_Update(
   visualState,
   clrDodgerBlue,   // 0 のときの色
   clrIndianRed     // 1 のときの色
);

-1 を渡した場合は背景も帯も表示されません。
0 または 1 のときのみ描画されます。

④ OnDeinit() でクリーンアップ


VisualMode_Deinit();

設計思想:ロジックと描画を分離する

このライブラリの本質は「色分け」ではありません。

ロジックと描画を分離する設計

これにより、

  • ロジックを変更しても描画は壊れない
  • 他EAへ流用できる
  • 機能追加しても保守しやすい
  • 外注時の仕様説明が明確になる

この考え方(mqh化・インクルード管理)の基本は、以下の記事で詳しく解説しています。
【MT4/MQL4】EAソースコードを整理する方法|mqh化・インクルード管理で見やすく効率化


補足:相場判定ロジックと組み合わせると強い

VisualMode.mqh は「状態を表示する」ための部品です。
判定ロジックはすべてEA側で自由に定義できます。

例:

  • ADXでトレンド/レンジ判定
  • 一目均衡表の三役好転/逆転
  • 移動平均線より上/下
  • 売買許可/停止モード
  • ナンピン段階表示

特に、ADXを使ったレンジ・トレンド判定を組み込むことで、 EAの相場モード管理がより明確になります。

👉 MT4でレンジ相場を自動判定する方法|ADXでトレンド判定する実装例

まずは相場環境の判定ロジックを設計し、 その状態を VisualMode.mqh で可視化する、 という流れが最も実務的です。

使用例:移動平均線より上なら青、下なら赤


double ma = iMA(NULL,0,50,0,MODE_SMA,PRICE_CLOSE,0);
double price = Close[0];

int state = -1;   // 初期は表示なし

if(price > ma)
   state = 1;      // モードB
else if(price < ma)
   state = 0;      // モードA

VisualMode_Update(
   state,
   clrRed,          // 0 のときの色
   clrBlue          // 1 のときの色
);

表示用に -1 / 0 / 1 に変換して渡すだけです。

VisualMode.mqh 側を変更する必要はありません。
ロジックの意味づけはすべてEA側で自由に定義できます。


まとめ

EA開発は、ロジックだけでなく「状態管理」まで含めて完成します。
VisualMode.mqh は、状態を視覚化するための基盤ライブラリです。

まずは1つのEAに組み込み、
「どのタイミングで、どの状態になっているか?」を見える化してみてください。
検証効率が一段上がります。

コメント

タイトルとURLをコピーしました