MQL5パネルEA・チャートUI実務ノート|表示系と判定系を分ける設計

EAファンクラブ

MQL5でパネルEAや裁量補助EAを作る場合、チャート上にボタン、ラベル、ステータス表示、価格ライン、状態パネルなどを配置することがあります。

こうしたチャートUIは、利用者にとって分かりやすい反面、設計を間違えるとEA本体の不安定化につながります。ボタンを押した瞬間に直接発注してしまう、表示ラベルの文字を判定に使ってしまう、Objectが残って誤参照される、毎tickで表示を作り直して重くなる、といった問題が起きやすくなります。

パネルEA・チャートUIで重要なのは、表示系と判定系を分けることです。UIは状態を表示し、操作要求を受け付ける層です。売買判定、発注、決済、リスク制御は、UIとは別のruntime stateやexecution層で扱う必要があります。

この記事では、MQL5パネルEA・チャートUIを安全に扱うための設計判断を、開発実務ノートとして整理します。完成EAソース全文、外部シート制御ロジック、認証ロジック、endpoint、token、URL実値、実運用set値、中核Entry条件は公開しません。

本記事は、投資判断や売買指示ではなく、MQL5のパネルEA・チャートUIを設計・検証・サポートしやすくするための技術記事です。

この記事で扱う実務課題

項目この記事で扱う内容扱わない内容
目的パネルEA・チャートUIで表示系と判定系を分ける設計利益を狙う売買ロジック、具体的なEntry条件
主な対象OBJ_LABEL、OBJ_BUTTON、OnChartEvent、UI request、runtime state、Object管理完成EAソース全文、実運用コード全文
設計観点誤操作防止、表示崩れ防止、Object残存対策、ログ追跡、販売後サポート認証ロジック、外部制御、実運用set値
コード例一般化したUI request、PanelState、OnChartEvent、表示更新例実発注処理、実Entry条件、独自優位性のある判定式
読者MQL5開発者、パネルEAを依頼したい人、検証担当者、販売前チェック担当者売買判断や推奨設定を知りたい人

なぜ表示系と判定系を分ける必要があるのか

パネルEAでは、画面に表示されている情報と、EA内部の真の状態が一致しているように見えます。しかし、表示はあくまで結果です。EAの判定や実行の真実は、runtime state、position snapshot、entry candidate、execution resultなどで管理するべきです。

表示系と判定系を混ぜると、次のような問題が起きます。

問題起きる原因分けるべき責務
表示はREADYなのに発注しないUI表示とruntime stateがずれているUI / runtime
ボタンを押したら即発注されるOnChartEventから直接OrderSendしているUI request / execution
古いラインを判定に使う残存Objectをruntime stateとして扱っているObject表示 / 判定状態
毎tickで重くなる表示Objectを毎回削除・再作成しているrender / maintenance
他EAや手動ラインを消すObject名prefixやowner判定がないObject管理 / cleanup
ログを見ても操作理由が分からないUI操作、request、execution結果が同じログになっているUI / request / execution / log

UIは、EA内部状態を表示するための層です。UIの文字やObject状態を読み返して売買判定に使う設計は避けるべきです。

パネルEAで分けるべき責務

パネルEAでは、通常のEA設計に加えて、UI関係の責務を明確に分けます。

責務役割混同すると起きる問題
runtime stateEA内部の真の状態を保持する表示と内部状態がずれる
UI renderruntime stateを画面に表示する表示更新失敗が判定に影響する
UI requestクリック操作を操作要求として受け取るボタン連打や誤クリックが直接発注につながる
execution発注・決済・modifyを実行するUI操作と注文結果が混ざる
risk / gate実行前の安全確認を行うクリックだけでrisk確認を飛ばす
Object lifecycleObject作成・更新・削除・残存監査を扱うObject残存や誤削除が起きる
log操作、表示、実行、失敗理由を記録する問い合わせ時に原因を追えない

特に重要なのは、UI requestとexecutionを分けることです。ボタンを押したことと、発注してよいことは別です。

OnChartEventから直接発注しない

OnChartEventは、チャート上のクリックやキー操作などを受け取るためのイベント関数です。パネルEAでは、OBJ_BUTTONをクリックした時にOnChartEventで処理することがあります。

ただし、OnChartEventから直接OrderSendや決済処理へ進む設計は避けるべきです。

直接実行する設計起きやすい問題
クリック直後にOrderSendするspread、保有上限、duplicate gate、risk確認を飛ばしやすい
クリック連打をそのまま処理する重複発注や連続決済につながる
UI操作と注文結果を同じログにする操作要求なのか実行結果なのか分からなくなる
ボタン表示だけで許可状態を判断する内部状態と表示がずれた時に誤操作につながる

安全な設計では、OnChartEventでは「ユーザーが何を要求したか」だけを記録し、実行前確認は別の層で行います。

UI requestとは何か

UI requestとは、ボタン操作やパネル操作を、即実行ではなく操作要求として保持する考え方です。

たとえば、BUYボタンが押された場合、すぐにOrderSendするのではなく、「BUY_REQUESTが発生した」としてruntimeに渡します。その後、execution層へ進む前に、AutoTrading、spread、ポジション状態、重複発注防止、risk条件などを確認します。

段階役割ログ例
UI clickユーザー操作を受けるBUTTON_CLICK
UI request操作要求として保存するUI_REQUEST_SET
gate / risk実行してよいか確認するUI_REQUEST_BLOCK / GATE_PASS
execution実行処理へ渡すROUTE_TO_EXECUTION
result結果を確認するORDER_RESULT / CLOSE_RESULT

このように分けると、クリックされたが実行前条件で止まったのか、実行へ進んだがOrderSendで失敗したのかを切り分けやすくなります。

runtime stateを表示の真実にする

パネル表示は、runtime stateから作るべきです。チャート上のラベル文字を読み返してEAの状態を決める構造は避けます。

たとえば、画面に「READY」と表示されているかどうかではなく、EA内部のruntimeReady、tradeAllowed、entryBlockedReason、positionStateなどをもとに表示を作ります。

扱い推奨理由
判定の真実runtime state表示遅延やObject残存の影響を受けにくい
表示runtime stateから生成内部状態と画面表示を対応させやすい
操作UI requestとして受けるクリックと実行を分けられる
ログUI、request、executionを分ける問い合わせ時に原因を追いやすい

UIは状態を見せるためのものです。UIを状態の保存場所として使うと、表示崩れやObject残存がEAの判定に影響してしまいます。

Object名prefixと所有範囲を決める

チャートUIを使う場合、Object名のprefixを決めることが重要です。

prefixがないと、自EAのObject、他EAのObject、手動で引いたラインを区別しにくくなります。その結果、他EAや利用者のObjectを誤って削除・更新する可能性があります。

Object分類扱い注意点
自EAのUI Objectprefixで識別して管理するボタン、ラベル、パネル枠など
自EAの表示ライン表示専用か判定参照対象かを分ける平均ライン、TP目安、Trail目安など
他EAのObject原則触らないprefix不一致なら対象外
手動Object原則触らない利用者の作業内容を壊さない
残存Objectstartup auditやresidual ignoreで扱う無条件に実ロジックへ使わない

Object cleanupでは、「消したいものを全部消す」のではなく、「自EA所有が明確なものだけを対象にする」ことが重要です。

実コード例1:UI requestを構造体で扱う

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したUI request例です。
// 実運用EAの完成ソースではありません。

enum UiRequestType
{
   UI_REQUEST_NONE = 0,
   UI_REQUEST_BUY,
   UI_REQUEST_SELL,
   UI_REQUEST_CANCEL
};

struct UiRequest
{
   UiRequestType type;
   datetime requestedAt;
   string reason;
   bool handled;
};

UiRequest g_uiRequest;

void ClearUiRequest()
{
   g_uiRequest.type = UI_REQUEST_NONE;
   g_uiRequest.requestedAt = 0;
   g_uiRequest.reason = "NONE";
   g_uiRequest.handled = true;
}

void SetUiRequest(UiRequestType type, string reason)
{
   g_uiRequest.type = type;
   g_uiRequest.requestedAt = TimeCurrent();
   g_uiRequest.reason = reason;
   g_uiRequest.handled = false;

   Print("DIAG/UI_REQUEST: event=SET",
         " type=", (int)type,
         " reason=", reason);
}

この例では、クリック操作を即実行せず、UiRequestとして保持しています。発注や決済へ進むかどうかは、別のgateやexecution層で判断します。

実コード例2:OnChartEventではrequest化だけ行う

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したOnChartEvent例です。
// 実運用EAの完成ソースではありません。

string UiPrefix()
{
   return "EAFC_UI_";
}

string UiObjectName(string part)
{
   return UiPrefix() + part;
}

bool IsOwnUiObject(string name)
{
   return (StringFind(name, UiPrefix()) == 0);
}

void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
   if(id != CHARTEVENT_OBJECT_CLICK)
      return;

   if(!IsOwnUiObject(sparam))
      return;

   Print("DIAG/UI: event=BUTTON_CLICK",
         " object=", sparam);

   if(sparam == UiObjectName("BuyButton"))
   {
      SetUiRequest(UI_REQUEST_BUY, "BUY_BUTTON_CLICK");
      return;
   }

   if(sparam == UiObjectName("SellButton"))
   {
      SetUiRequest(UI_REQUEST_SELL, "SELL_BUTTON_CLICK");
      return;
   }

   if(sparam == UiObjectName("CancelButton"))
   {
      SetUiRequest(UI_REQUEST_CANCEL, "CANCEL_BUTTON_CLICK");
      return;
   }

   Print("DIAG/UI: event=CLICK_IGNORED",
         " reason=UNKNOWN_OBJECT",
         " object=", sparam);
}

この例では、OnChartEventから直接OrderSendや決済処理へ進んでいません。自EAのUI Objectかを確認し、対象ボタンに応じてUI requestを作るだけにしています。

実コード例3:runtime stateからパネル表示を作る

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。

// 学習用に一般化したPanelState例です。
// 実運用EAの完成ソースではありません。

struct PanelState
{
   bool runtimeReady;
   bool tradeAllowed;
   string modeText;
   string statusText;
   string lastReason;
};

PanelState BuildPanelState()
{
   PanelState state;
   state.runtimeReady = true;
   state.tradeAllowed = true;
   state.modeText = "MONITOR";
   state.statusText = "READY";
   state.lastReason = "OK";

   return state;
}

void TracePanelState(const PanelState &state)
{
   Print("DIAG/UI_RENDER: event=STATE",
         " ready=", state.runtimeReady,
         " trade_allowed=", state.tradeAllowed,
         " status=", state.statusText,
         " reason=", state.lastReason);
}

PanelStateは、表示のために必要な状態だけをまとめた構造です。画面上のラベル文字を読み返して判定するのではなく、runtime stateから表示内容を作ります。

実コード例4:UI requestをexecution前のgateへ渡す

以下は、設計判断を理解するために一般化した学習用コード例です。完成EAのソース全文ではありません。実発注処理や中核Entry条件は含めていません。

// 学習用に一般化したUI request処理例です。
// 実運用EAの完成ソースではありません。

bool CanProcessUiRequest(const UiRequest &request)
{
   if(request.type == UI_REQUEST_NONE)
      return false;

   if(request.handled)
      return false;

   // 実際のEAでは、AutoTrading、spread、position、
   // duplicate gate、riskなどを別責務で確認します。

   return true;
}

void ProcessUiRequest()
{
   if(!CanProcessUiRequest(g_uiRequest))
      return;

   Print("DIAG/UI_REQUEST: event=PROCESS_START",
         " type=", (int)g_uiRequest.type,
         " reason=", g_uiRequest.reason);

   if(g_uiRequest.type == UI_REQUEST_BUY)
   {
      Print("DIAG/UI_REQUEST: event=ROUTE",
            " target=BUY_EXECUTION_CHECK");
   }
   else if(g_uiRequest.type == UI_REQUEST_SELL)
   {
      Print("DIAG/UI_REQUEST: event=ROUTE",
            " target=SELL_EXECUTION_CHECK");
   }
   else if(g_uiRequest.type == UI_REQUEST_CANCEL)
   {
      Print("DIAG/UI_REQUEST: event=ROUTE",
            " target=CANCEL_REQUEST");
   }

   ClearUiRequest();
}

UI requestを処理する場合も、すぐに発注へ進むのではなく、execution前の確認へ渡します。クリック操作、発注前gate、OrderSend結果を分けることで、不具合調査がしやすくなります。

表示更新を毎tickで重くしない

パネルEAでは、表示更新の頻度にも注意が必要です。

OnTickごとにすべてのObjectを削除して再作成すると、チャートがちらつき、MT5が重くなり、Object残存や表示崩れの原因になります。

避けたい設計推奨する設計
毎tickで全Objectを削除・再作成する初回作成後はテキストや色だけ差分更新する
毎tickで全Objectを走査するOnTimerや状態変化時のmaintenanceへ分ける
表示失敗でEA本体を止める表示はbest-effortにし、売買処理と分ける
毎tickでUI_RENDERログを大量に出す状態変化時または一定間隔でsummary化する
座標やサイズを毎回再設定する初期化時に設定し、必要時だけ更新する

表示更新は重要ですが、売買判定や既存ポジション管理より優先されるべきではありません。表示系は軽く、追跡可能で、失敗しても本体処理へ過度に波及しない設計が安全です。

UI操作ログで確認するポイント

パネルEAの不具合調査では、UI操作、request化、実行前確認、execution結果を分けてログで追えることが重要です。

ログ区分ログ例確認できること
UIBUTTON_CLICK、CLICK_IGNOREDどのObjectがクリックされたか
UI_REQUESTSET、PROCESS_START、BLOCK、ROUTE操作がrequest化され、処理対象になったか
GATEGATE_PASS、GATE_BLOCK実行前安全確認を通過したか
RISKRISK_BLOCK、LOT_INVALIDrisk条件で止めたか
ORDERORDER_SEND_OK、ORDER_SEND_FAIL注文結果
UI_RENDERSTATE、UPDATE、SKIP表示更新の状態
OBJECT_AUDITCREATE_OK、CREATE_FAIL、RESIDUAL_IGNOREObject作成・残存・監査状況

「ボタンを押したのに動かない」という相談でも、UIクリックが認識されていないのか、request化されたがGATEで止まったのか、executionで失敗したのかは別です。

Object cleanupとOnDeinitの考え方

パネルEAでは、EA削除時にパネル部品を消したい場合があります。

自EA所有が明確なUI Objectであれば、OnDeinitで整理しやすい対象です。ただし、価格ラインや残存監査対象のObjectまで広範囲に消す設計は避けるべきです。

Object種別OnDeinitでの扱い理由
自EAのボタン削除候補UI部品として所有範囲が明確なため
自EAのステータスラベル削除候補表示専用で再作成しやすいため
平均ライン・Trailライン方針次第表示専用かロジック参照対象かで扱いが変わるため
手動ライン削除しない利用者の作業内容を壊さないため
他EAのObject削除しない他EAへ影響するため

OnDeinitで何を消すかは、Object名prefix、Object種別、所有範囲を基準にします。広範囲のObject走査や全削除は、EA削除時の不安定化につながる場合があります。

よくある失敗例

失敗1:OnChartEventから直接OrderSendする

クリックイベントから直接発注すると、spread、risk、duplicate gate、position stateの確認を飛ばしやすくなります。OnChartEventではUI requestを作るまでに留め、実行はexecution層へ渡します。

失敗2:表示ラベルの文字を判定に使う

ラベルは表示結果です。判定の真実はruntime stateで管理し、ラベルはそこから生成するべきです。

失敗3:毎tickでObjectを作り直す

毎tickでObjectDeleteとObjectCreateを繰り返すと、ちらつき、重さ、残存Objectの原因になります。初回作成後は差分更新を基本にします。

失敗4:Object名prefixがない

prefixがないと、自EAのObject、他EAのObject、手動Objectを区別できません。誤削除や誤更新を防ぐため、Object名の命名規則を決めます。

失敗5:UI表示失敗でEA本体を止める

表示更新失敗と売買処理の失敗は分けるべきです。表示はbest-effort、判定とexecutionはruntime stateで管理します。

失敗6:ボタン連打対策がない

ボタン連打をそのまま処理すると、重複requestや重複発注につながります。UI requestのhandled管理、cooldown、duplicate gateを使います。

失敗7:表示系とObject lifecycleを分けていない

パネル部品、価格ライン、残存Object、ロジック参照Objectは扱いが違います。すべてを同じcleanup方針にすると、表示崩れや誤参照につながります。

導入前・開発依頼前に整理する情報

パネルEAやチャートUI付きEAを開発・改修する場合、次の情報を整理しておくと仕様確認がスムーズになります。

  • 表示したい項目
  • ボタン操作の種類
  • クリック後に即実行するのか、確認段階を挟むのか
  • BUY / SELL / CANCEL / RESETなどの操作範囲
  • UI requestの有効期限
  • ボタン連打対策
  • runtime stateとして保持する項目
  • UIに表示する項目
  • Object名prefix
  • OnDeinitで削除するUI Objectの範囲
  • 残す価格ラインと消すパネル部品の違い
  • UI操作ログの粒度
  • スマホ・VPS・複数チャートでの表示確認方針

パネルEAは見た目の仕様が目立ちますが、実務上は「どの操作がどのrequestになり、どのgateを通り、どのexecutionへ進むか」を先に整理することが重要です。

関連する技術講座・確認ページ

ページ確認できること
技術講座ハブMQL5やMT5開発に関する講座一覧
MQL5チャートオブジェクト・UI表示完全ガイドOBJ_LABEL、OBJ_BUTTON、チャートUIの基本
MQL5デバッグ・ログファースト開発完全ガイドログ確認、デバッグ、原因調査の基本
MT5開発依頼前に用意する資料まとめ仕様書、setファイル、ログ、スクリーンショットの整理
不具合報告・調査依頼について不具合相談前に送る情報
よくある質問導入、確認、相談前のFAQ
免責事項・リスク説明投資判断、損益、利用上の注意に関する確認

FAQ

パネルEAではボタンを押したらすぐ発注する設計でもよいですか?

避けた方が安全です。クリック操作はUI requestとして受け取り、spread、position、duplicate gate、riskなどの確認を通してからexecutionへ渡す設計が安全です。

表示ラベルの文字をEA内部の判定に使ってよいですか?

避けるべきです。表示ラベルはruntime stateを表示した結果です。判定の真実はruntime state、position snapshot、entry candidateなどで管理します。

OnChartEventでは何をするべきですか?

OnChartEventでは、クリックされたObjectを確認し、UI requestを作るところまでに留めるのが安全です。発注・決済・risk判断は別の責務へ分けます。

Object名にprefixは必要ですか?

必要です。prefixがないと、自EAのObject、他EAのObject、手動Objectを区別できず、誤削除や誤更新の原因になります。

EA削除時にパネル部品は消してよいですか?

自EA所有が明確なUI Objectであれば削除候補になります。ただし、価格ラインや残存監査対象のObjectまで広範囲に消す設計は慎重に判断する必要があります。

表示更新は毎tickで行ってよいですか?

内容によりますが、毎tickでObject削除・再作成するのは避けるべきです。初回作成後は差分更新、状態変化時更新、一定間隔更新などに分ける方が安全です。

パネル表示が失敗したらEA本体も停止すべきですか?

通常は分けて考えます。表示系の失敗と売買処理の失敗は別です。表示はbest-effort、判定やexecutionはruntime stateで管理します。

実装コードがなくてもパネルEAの相談はできますか?

可能です。表示項目、操作ボタン、クリック後の挙動、確認段階の有無、Object cleanup方針、ログに残したい項目が整理されていれば、相談を進めやすくなります。

関連する開発実務ノート

パネルEAやチャートUIを扱う場合は、表示系だけでなく、EA本体の責務分離、ログ設計、長時間稼働、商品化前のUI整理もあわせて確認しておくと安全です。

まとめ

MQL5パネルEA・チャートUIでは、見た目を作ることよりも、表示系と判定系を分けることが重要です。

特に、次の4点を分けると、誤操作、表示崩れ、重複発注、Object残存、不具合調査の問題を減らしやすくなります。

  • runtime state:EA内部の真の状態を保持する
  • UI render:runtime stateを画面へ表示する
  • UI request:クリック操作を即実行せず、操作要求として扱う
  • execution / risk:発注・決済・安全確認をUIとは別責務で扱う

OnChartEventは、クリックイベントを受ける入口です。そこから直接OrderSendや決済へ進むのではなく、UI requestを作り、別のexecution層で安全確認してから処理する構成が安全です。

また、Object名prefix、Object lifecycle、OnDeinitでのcleanup範囲、表示更新頻度、UI操作ログを設計しておくことで、販売後サポートや不具合調査もしやすくなります。

完成EAの中核ロジックを公開しなくても、パネルEA・チャートUIの責務分離を理解しておくことで、開発依頼、既存EA改修、検証、不具合調査、販売後サポートの品質を上げやすくなります。

ABOUT ME
記事URLをコピーしました