MQL5パネルUI・チャートObject表示を実コードで解説|表示系と判定系を分ける理由
MQL5でパネルEAや裁量補助EAを作る場合、チャート上にラベル、ボタン、ステータス枠、ラインなどを表示することがあります。
しかし、パネルUIやチャートObjectは、見た目を作るだけではありません。表示系と判定系を混同すると、ボタン表示が変わっただけで売買挙動が変わる、古いObjectを判定に使ってしまう、時間足変更後に表示が崩れる、EA削除時にObjectが残る、といった問題につながります。
この記事では、MQL5のパネルUI・チャートObject表示を、学習用に一般化したコード断片で解説します。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開しません。
扱うのは、OBJ_LABEL、OBJ_BUTTON、OnChartEvent、UI状態管理、表示系と判定系の責務分離、表示更新ログ、Object名のprefix設計です。
- この記事で扱う範囲
- パネルUIで起きやすい問題
- 表示系と判定系を分ける理由
- Object名のprefix設計
- OBJ_LABELとOBJ_BUTTONの違い
- OnChartEventで直接発注しない理由
- 実コード断片1:UI Object名を作る
- 実コード断片2:ラベルを作成・更新する
- 実コード断片3:ボタンを作成する
- 実コード断片4:UI requestを作る
- 実コード断片5:OnChartEventでクリックを受ける
- 実コード断片6:UI requestを安全に処理する
- 実コード断片7:パネル表示をruntime stateから更新する
- 表示更新を毎tickで重くしない
- 表示系の失敗は売買系へ波及させない
- OnDeinitでのUI cleanup
- よくある失敗例
- ログで確認するポイント
- 開発依頼前に整理する情報
- 公開しない情報
- FAQ
- 関連ページ
- まとめ
この記事で扱う範囲
| 項目 | この記事で扱う内容 | 扱わない内容 |
|---|---|---|
| 目的 | パネルUIとチャートObjectを安全に扱う設計 | 利益を狙う売買ロジック、具体的なエントリー条件 |
| 主な機能 | OBJ_LABEL、OBJ_BUTTON、OnChartEvent、表示更新helper | 完成EAソース全文、実運用コード全文 |
| 設計対象 | 表示系と判定系の分離、UIイベント、Object命名、表示更新 | 外部制御、認証、実運用set値 |
| コード例 | 学習用に簡略化した短いコード断片 | 中核エントリー条件、独自優位性のある判定式 |
| 確認対象 | UI_RENDER、BUTTON_CLICK、UI_REQUEST、OBJECT_UPDATEログ | 推奨ロット、推奨銘柄、売買判断 |
パネルUIで起きやすい問題
MQL5のパネルUIでは、見た目の問題だけでなく、EAの安全性に関わる問題が起きることがあります。
| 現象 | 原因になりやすい設計 | 改善方針 |
|---|---|---|
| ボタンが残る | Object lifecycleが整理されていない | 自EA所有のUI Objectだけを対象に管理する |
| クリック後に誤発注する | OnChartEventから直接発注している | UI requestとexecutionを分ける |
| 表示と内部状態がずれる | 画面表示を判定の真実として使っている | runtime stateを真実にし、UIは表示補助にする |
| 毎tickで表示がちらつく | Objectを毎回削除・再作成している | 既存Objectを差分更新する |
| 他EAや手動Objectを消す | prefixなしでObjectDeleteしている | owner prefixとobject kindで対象を限定する |
| 時間足変更後に崩れる | 初期化・再描画・残存監査が不足している | OnInitで再構築し、必要に応じてstartup auditする |
パネルUIは利用者にとって重要ですが、EAの売買判定そのものではありません。表示は表示、判定はruntime state、実行はexecutionとして分けることが重要です。
表示系と判定系を分ける理由
パネルEAでは、画面に表示されている文字やボタン状態を、そのまま売買判定の根拠にしてはいけません。
たとえば、ボタンに「READY」と表示されているから発注可能、ラベルに「BUY」と表示されているから買い判定、ラインがあるからTrail中、といった設計は危険です。
| 責務 | 役割 | 保持する情報 |
|---|---|---|
| runtime state | EA内部の真の状態 | ready、mode、position state、request state |
| signal | 判定候補を作る | signal side、score、reason |
| execution | 発注・決済を行う | order request、retcode、ticket |
| UI | 状態を表示し、操作要求を受ける | label text、button state、panel color |
| log | 状態変化と理由を記録する | event、reason、detail |
UIはあくまでruntime stateを表示するための層です。UIに表示されている文字を読み返して判定に使うのではなく、内部状態をもとに表示を更新します。
Object名のprefix設計
チャート上のObjectを安全に管理するには、Object名にprefixを付けて、自EAが作成したものだけを識別できるようにします。
Object名には、少なくとも次の情報を含めると管理しやすくなります。
- EAまたはシリーズ識別用のprefix
- UIかラインかラベルかのkind
- 用途名
- 必要に応じてsideやlogic id
たとえば、学習用には次のような命名が考えられます。
EAFC_UI_StatusLabel
EAFC_UI_BuyButton
EAFC_UI_SellButton
EAFC_UI_ModeLabel
EAFC_LINE_Avg_Buy
EAFC_LINE_Trail_Sellprefixがないと、他EAや手動Objectを誤って削除・更新する危険があります。Object操作では、必ず自EA所有かどうかを確認する方針が重要です。
OBJ_LABELとOBJ_BUTTONの違い
パネルUIでよく使うObjectには、OBJ_LABELとOBJ_BUTTONがあります。
| Object種別 | 用途 | 注意点 |
|---|---|---|
| OBJ_LABEL | 状態、説明、数値、警告などの表示 | 表示専用。判定の真実として使わない |
| OBJ_BUTTON | クリック操作、モード切替、確認操作 | クリックで直接発注せず、request化する |
| OBJ_RECTANGLE_LABEL | 背景枠、パネル枠 | 重ね順、座標、サイズを整理する |
| OBJ_HLINE | 価格ライン、目安ライン | 表示専用かロジック参照対象かを分ける |
| OBJ_TEXT | 価格位置に紐づく文字表示 | チャートスケールや表示位置の影響を受ける |
OBJ_BUTTONを使う場合でも、OnChartEvent内で直接注文を送信するのではなく、「ユーザーがクリックした」というrequestを作り、execution側で安全確認を行ってから実行します。
OnChartEventで直接発注しない理由
OnChartEventは、チャート上のクリックやキー操作などのイベントを受け取る関数です。
ボタン操作を扱えるため便利ですが、OnChartEventから直接OrderSendや決済処理へ進む設計は避けた方が安全です。
理由は次の通りです。
- クリックイベントと実行条件確認が混ざる
- 誤クリック時のガードが弱くなりやすい
- ログ上、UI操作と発注実行の境界が分かりにくい
- AutoTrading、spread、ポジション状態、重複制御を飛ばす危険がある
- 後からconfirmやREADY制御を追加しにくい
安全な設計では、OnChartEventは「UI requestを作る場所」として扱い、実際のexecutionは別の関数で行います。
実コード断片1:UI Object名を作る
以下は、実際のEAで使う考え方を学習用に簡略化したコード例です。完成EAのソース全文ではなく、Object命名の構造を理解するための抜粋です。
// 学習用に一般化したUI Object名生成例です。
// 実運用EAの完成ソースではありません。
string UiPrefix()
{
return "EAFC_UI_";
}
string UiObjectName(string partName)
{
return UiPrefix() + partName;
}
bool IsOwnUiObject(string name)
{
return (StringFind(name, UiPrefix()) == 0);
}
string BuildSidePartName(string baseName, string side)
{
return baseName + "_" + side;
}実際のEAでは、認証、外部制御、口座条件、エラー処理、ログ出力などを分けて設計します。この記事では、公開できる範囲の構造だけを取り上げています。
このコードの役割
| 処理 | 役割 |
|---|---|
| UiPrefix | 自EAのUI Objectであることを示すprefixを返す |
| UiObjectName | UI部品名を統一形式で作る |
| IsOwnUiObject | 他EAや手動Objectと区別する |
| BuildSidePartName | BUY / SELLなど方向付き部品名を作る |
Object名の作り方をhelperにまとめると、ボタンやラベルが増えても命名ルールを揃えやすくなります。
実コード断片2:ラベルを作成・更新する
以下は、OBJ_LABELを作成し、すでに存在する場合はテキストだけ更新する学習用コード例です。
// 学習用に一般化したラベル更新例です。
// 実運用EAの完成ソースではありません。
bool EnsureLabel(string name, int x, int y)
{
if(ObjectFind(0, name) >= 0)
return true;
ResetLastError();
if(!ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0))
{
Print("DIAG/UI: event=CREATE_FAIL",
" kind=LABEL",
" name=", name,
" error=", GetLastError());
return false;
}
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 10);
Print("DIAG/UI: event=CREATE_OK",
" kind=LABEL",
" name=", name);
return true;
}
void SetLabelText(string name, string text)
{
if(ObjectFind(0, name) < 0)
return;
ObjectSetString(0, name, OBJPROP_TEXT, text);
}この例では、ラベルがなければ作成し、存在する場合は再作成しません。毎tickで削除と作成を繰り返すのではなく、既存Objectを差分更新する方針です。
このコードの役割
| 処理 | 役割 |
|---|---|
| EnsureLabel | ラベルが存在しなければ作成する |
| ObjectFind | 既存Objectの有無を確認する |
| ObjectCreate | OBJ_LABELを作成する |
| ObjectSetInteger | 座標、角、フォントサイズなどを設定する |
| SetLabelText | 既存ラベルの文字だけ更新する |
表示更新は、売買判定ではなくUI層の責務です。ラベルに表示した文字を後から読み取って判定する構造は避けます。
実コード断片3:ボタンを作成する
以下は、OBJ_BUTTONを作成する学習用コード例です。ボタン作成と、クリック後の実行処理は分けて考えます。
// 学習用に一般化したボタン作成例です。
// 実運用EAの完成ソースではありません。
bool EnsureButton(string name, string text, int x, int y, int width, int height)
{
if(ObjectFind(0, name) >= 0)
return true;
ResetLastError();
if(!ObjectCreate(0, name, OBJ_BUTTON, 0, 0, 0))
{
Print("DIAG/UI: event=CREATE_FAIL",
" kind=BUTTON",
" name=", name,
" error=", GetLastError());
return false;
}
ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER);
ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x);
ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y);
ObjectSetInteger(0, name, OBJPROP_XSIZE, width);
ObjectSetInteger(0, name, OBJPROP_YSIZE, height);
ObjectSetString(0, name, OBJPROP_TEXT, text);
Print("DIAG/UI: event=CREATE_OK",
" kind=BUTTON",
" name=", name);
return true;
}このコードは、ボタンを表示するだけの例です。クリックされた時に何をするかは、OnChartEvent側で受け取り、requestとしてruntimeへ渡します。
このコードの役割
| 処理 | 役割 |
|---|---|
| EnsureButton | ボタンが存在しなければ作成する |
| OBJ_BUTTON | チャート上のクリック可能なObjectを作る |
| OBJPROP_XSIZE / YSIZE | ボタンサイズを設定する |
| OBJPROP_TEXT | ボタンに表示する文字を設定する |
| CREATE_OK | ボタン作成が成功したことをログへ残す |
ボタン表示が成功していることと、発注可能であることは別です。UI表示とexecution条件は必ず分けます。
実コード断片4:UI requestを作る
以下は、ボタンクリックを直接実行せず、UI requestとして内部状態へ渡す学習用コード例です。
// 学習用に一般化した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;
};
UiRequest g_uiRequest;
void ClearUiRequest()
{
g_uiRequest.type = UI_REQUEST_NONE;
g_uiRequest.requestedAt = 0;
g_uiRequest.reason = "NONE";
}
void SetUiRequest(UiRequestType type, string reason)
{
g_uiRequest.type = type;
g_uiRequest.requestedAt = TimeCurrent();
g_uiRequest.reason = reason;
Print("DIAG/UI_REQUEST: event=SET",
" type=", (int)type,
" reason=", reason);
}UI requestを作ることで、クリック操作と実際のexecutionを分離できます。
このコードの役割
| 処理 | 役割 |
|---|---|
| UiRequestType | UIから来た操作要求の種類を定義する |
| UiRequest | 操作要求の種類、時刻、理由を保持する |
| ClearUiRequest | 処理済みまたは無効なrequestをクリアする |
| SetUiRequest | クリックされた操作をrequestとして記録する |
| UI_REQUESTログ | UI操作が発生したことをExpertsログで追えるようにする |
この時点では、まだ発注や決済を行いません。発注や決済を行う前に、AutoTrading、spread、保有状態、重複制御、risk条件などの確認が必要です。
実コード断片5:OnChartEventでクリックを受ける
以下は、OnChartEventでボタンクリックを受け取り、UI requestを作る学習用コード例です。
// 学習用に一般化したOnChartEvent例です。
// 実運用EAの完成ソースではありません。
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);
}この例では、クリックされたObjectが自EAのUI Objectかを確認し、対象ボタンに応じてrequestを作っています。
このコードの役割
| 処理 | 役割 |
|---|---|
| CHARTEVENT_OBJECT_CLICK | Objectクリックイベントだけを対象にする |
| IsOwnUiObject | 自EAのUI Object以外を無視する |
| BUTTON_CLICK | クリックされたObject名をログへ残す |
| SetUiRequest | クリック操作を内部requestへ変換する |
| CLICK_IGNORED | 未知のObjectクリックを無視したことを記録する |
OnChartEventはUIイベントを受ける場所であり、executionを直接行う場所ではありません。
実コード断片6:UI requestを安全に処理する
以下は、UI requestを確認し、実行前ガードへ渡す考え方を示す学習用コード例です。実際の発注処理や中核エントリー条件は含めていません。
// 学習用に一般化したUI request処理例です。
// 実運用EAの完成ソースではありません。
bool CanProcessUiRequest()
{
// 実際はAutoTrading、spread、position、risk、duplicate gateなどを確認します。
return true;
}
void ProcessUiRequest()
{
if(g_uiRequest.type == UI_REQUEST_NONE)
return;
Print("DIAG/UI_REQUEST: event=PROCESS_START",
" type=", (int)g_uiRequest.type,
" reason=", g_uiRequest.reason);
if(!CanProcessUiRequest())
{
Print("DIAG/UI_REQUEST: event=BLOCK",
" reason=PRECHECK_FAIL");
ClearUiRequest();
return;
}
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を受けても、すぐに発注へ進まず、まず実行前確認へ渡しています。
このコードの役割
| 処理 | 役割 |
|---|---|
| CanProcessUiRequest | 実行前に必要な安全確認を行う入口 |
| PROCESS_START | UI request処理の開始をログへ残す |
| BLOCK | 安全条件を満たさず処理を止めたことを示す |
| ROUTE | 次にどの実行確認へ進むかを示す |
| ClearUiRequest | 処理済みrequestを残さない |
このように、UI操作とexecutionを分けることで、ボタンクリックから直接発注へ進む事故を防ぎやすくなります。
実コード断片7:パネル表示をruntime stateから更新する
以下は、runtime stateをもとにパネル表示を更新する学習用コード例です。
// 学習用に一般化したパネル表示更新例です。
// 実運用EAの完成ソースではありません。
struct PanelState
{
bool runtimeReady;
string modeText;
string statusText;
string lastReason;
};
PanelState BuildPanelState()
{
PanelState state;
state.runtimeReady = true;
state.modeText = "MONITOR";
state.statusText = "READY";
state.lastReason = "OK";
return state;
}
void RenderPanel(const PanelState &state)
{
string statusName = UiObjectName("StatusLabel");
string modeName = UiObjectName("ModeLabel");
EnsureLabel(statusName, 20, 20);
EnsureLabel(modeName, 20, 40);
SetLabelText(statusName, "Status: " + state.statusText);
SetLabelText(modeName, "Mode: " + state.modeText);
Print("DIAG/UI_RENDER: event=UPDATE",
" status=", state.statusText,
" reason=", state.lastReason);
}この例では、UI表示をPanelStateから更新しています。画面上のラベルを読み返してEAの状態を決めるのではなく、runtime stateから表示を作ります。
このコードの役割
| 処理 | 役割 |
|---|---|
| PanelState | 表示に必要な状態だけをまとめる |
| BuildPanelState | runtime stateから表示用stateを作る |
| RenderPanel | 表示用stateをラベルへ反映する |
| UI_RENDER | 表示更新が行われたことをログへ残す |
UIはruntime stateの結果を表示する層です。UIそのものを判定の真実として扱わないことが重要です。
表示更新を毎tickで重くしない
パネルUIは、毎tickで更新しすぎると重くなります。
特に、次の処理は避けた方が安全です。
- 毎tickで全Objectを削除して再作成する
- 毎tickで全ラベルの座標やサイズを再設定する
- 毎tickで大量のUI_RENDERログを出す
- 変化していない文字列を何度も更新する
- 表示更新失敗でEA本体を止める
表示更新は、初期化時、状態変化時、または一定間隔で行うと安定しやすくなります。
表示系の失敗は売買系へ波及させない
パネルUIの表示失敗は、可能な限り売買系へ直接波及させない設計にします。
| 状態 | 推奨する扱い |
|---|---|
| ラベル作成に失敗 | ログに残し、表示だけbest-effortで継続 |
| ボタン作成に失敗 | 手動操作系を無効化し、ログに残す |
| 表示更新が遅延 | runtime stateを優先し、表示は次回更新で補正 |
| クリック対象が未知 | 無視してログに残す |
| UI requestが古い | 有効期限切れとして破棄する |
表示系は利用者の確認に必要ですが、表示Objectの状態をそのまま発注や決済の根拠にしないことが重要です。
OnDeinitでのUI cleanup
UI Objectは、平均価格ラインやTrailラインなどの取引補助ラインとは異なり、自EA所有が明確なステータス表示として整理しやすい場合があります。
ただし、OnDeinitで広範囲のObjectを消すのではなく、prefixが一致する軽量なUI Objectだけを対象にします。
// 学習用に一般化したUI cleanup例です。
// 実運用EAの完成ソースではありません。
void DeleteOwnUiObjects()
{
for(int i = ObjectsTotal(0) - 1; i >= 0; i--)
{
string name = ObjectName(0, i);
if(!IsOwnUiObject(name))
continue;
ObjectDelete(0, name);
Print("DIAG/UI: event=DELETE",
" name=", name);
}
}
void OnDeinit(const int reason)
{
Comment("");
EventKillTimer();
DeleteOwnUiObjects();
Print("DIAG/DEINIT: event=UI_CLEANUP_DONE",
" reason=", reason);
}この例は、自EA所有が明確なUI Objectだけを対象にしています。実ロジックに関係する価格ラインや残存監査対象のObjectを、同じcleanupでまとめて消す設計は避けます。
よくある失敗例
失敗1:OnChartEventから直接発注する
ボタンクリックから直接発注へ進むと、precheck、duplicate gate、risk、position stateの確認を飛ばしやすくなります。UI requestを作り、execution側で安全確認してから処理します。
失敗2:表示ラベルの文字を判定に使う
ラベルは表示結果であり、判定の真実ではありません。EA内部のruntime stateを真実として扱い、ラベルはそこから作ります。
失敗3:毎tickでObjectを作り直す
毎tickでObjectDeleteとObjectCreateを繰り返すと、ちらつき、重さ、Object残存の原因になります。既存Objectを差分更新します。
失敗4:prefixなしでObjectを削除する
prefixなしでObjectDeleteすると、手動ラインや他EAのObjectまで巻き込む可能性があります。自EA所有のUI Objectだけを対象にします。
失敗5:UI表示失敗でEA本体を止める
表示系の失敗は、売買系と分けて扱う必要があります。表示はbest-effort、判定やexecutionはruntime stateで管理します。
ログで確認するポイント
パネルUI・チャートObject表示の問題を確認する時は、Expertsログで次の情報を見ます。
| ログ | 見るポイント |
|---|---|
| CREATE_OK | ラベルやボタンが作成できているか |
| CREATE_FAIL | ObjectCreate失敗時のerrorが確認できるか |
| BUTTON_CLICK | クリックされたObject名が確認できるか |
| UI_REQUEST SET | クリックがrequestへ変換されているか |
| UI_REQUEST BLOCK | 安全条件で止まった理由が分かるか |
| UI_RENDER UPDATE | runtime stateから表示更新されているか |
| UI_CLEANUP_DONE | EA終了時のUI cleanupが確認できるか |
ログ確認の基本は、次のページも参考にしてください。
開発依頼前に整理する情報
パネルEAや裁量補助EAの開発を依頼する場合、次の情報を整理しておくと仕様のすれ違いを減らせます。
- 表示したい項目
- ボタン操作の種類
- クリック後に即実行するのか、確認段階を挟むのか
- BUY / SELL / CANCEL / RESETなどの操作範囲
- 表示系と判定系を分けるか
- UI requestの有効期限
- Object名のprefix
- OnDeinitで削除するUI Objectの範囲
- 残すラインと消すパネル部品の違い
- UI操作ログの粒度
仕様書、setファイル、ログ、スクリーンショットを整理する場合は、次のページも確認してください。
MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット
公開しない情報
この記事では、MQL5のパネルUI・チャートObject表示を学ぶために、公開可能な範囲だけを一般化して解説しています。以下は公開しません。
- 完成EAソース全文
- 外部シート参照による動作制御ロジック
- 外部シートCSV取得、解析、時間枠、方向制御ロジック
- 認証、口座許可判定、購入者管理ロジック
- endpoint、token、URL、Google Sheet ID、Webhook URL、GAS URL
- APIキー、認証トークン、口座番号、サーバー名
- 実運用set値
- 中核エントリー条件
- 中核Trail / Nanpin判定
- 独自優位性のある売買判定式
- 利益保証、勝率保証、推奨ロット、推奨銘柄、推奨エントリー
本記事は、投資判断や売買指示ではなく、MQL5開発におけるパネルUI、チャートObject、OnChartEvent、表示系と判定系の分離を理解するための技術解説です。
FAQ
パネルUIの表示内容を売買判定に使ってよいですか?
避けた方が安全です。表示内容はruntime stateを表示した結果であり、判定の真実ではありません。売買判定は内部状態やsnapshotをもとに行い、UIは表示補助として扱います。
OnChartEventから直接発注してよいですか?
避けるべきです。OnChartEventではクリックを受け取り、UI requestを作るまでに留めます。実際の発注や決済は、precheck、risk、duplicate gateなどを通したexecution側で行います。
OBJ_LABELとOBJ_BUTTONは何が違いますか?
OBJ_LABELは表示用、OBJ_BUTTONはクリック操作用です。どちらもチャートObjectですが、役割が違います。表示Objectを判定の真実として使わないことが重要です。
毎tickでパネルを更新してもよいですか?
状態表示の内容によります。毎tickでObjectを削除・再作成するのは避けるべきです。既存Objectの文字だけ更新する、状態変化時に更新する、一定間隔で更新するなどの方法が安全です。
EA削除時にUI Objectは消してよいですか?
自EA所有が明確な軽量UI Objectであれば、OnDeinitで整理しやすい対象です。ただし、価格ラインや残存監査対象のObjectを広範囲にまとめて消す設計は避けるべきです。
Object名にprefixは必要ですか?
必要です。prefixがないと、他EAや手動Objectと区別できず、誤削除や誤更新の原因になります。自EA所有のObjectだけを扱える命名ルールが重要です。
このコードは完成EAとして使えますか?
いいえ。この記事のコード例は、パネルUI・チャートObject表示の考え方を理解するために簡略化した学習用コードです。完成EAとしてそのまま使うことは想定していません。
実際のEAソース全文は公開されていますか?
公開していません。完成EAソース全文、外部シート制御、認証、endpoint、token、URL、実運用set値、中核エントリー条件は公開対象外です。
関連ページ
| ページ | 確認できること |
|---|---|
| MQL5 EAのObject lifecycleを実コードで解説 | Object残存、OnDeinit cleanup、startup auditの考え方 |
| MQL5ログファースト設計を実コードで解説 | UI操作やObject更新をreason付きでログ確認する考え方 |
| MQL5 EAの基本イベント構造を実コードで解説 | OnInit / OnTick / OnDeinitの責務分離 |
| MQL5 CopyBufferとインジケーターハンドル管理を実コードで解説 | 表示系とは別に、インジケーター値取得を管理する考え方 |
| MT5のログ確認方法|Experts・Journalの見方 | ExpertsログとJournalログの基本確認 |
| MT5開発依頼前に用意する資料まとめ|仕様書・setファイル・ログ・スクリーンショット | 開発相談前に整理する資料 |
| 不具合報告・調査依頼について | 不具合相談前に送る情報 |
| 免責事項 | 投資判断、損益、利用上の注意に関する確認 |
| 投資助言を行わない方針 | 売買助言ではなく技術支援として扱う方針 |
まとめ
MQL5でパネルUIやチャートObjectを扱う場合、見た目を作ることよりも、表示系と判定系を分けることが重要です。
特に、次の4点を分けておくと、誤操作・表示崩れ・Object残存・判定混線を防ぎやすくなります。
- UI Object:OBJ_LABELやOBJ_BUTTONで状態表示・操作受付を行う
- runtime state:EA内部の真の状態を保持する
- UI request:クリック操作を直接実行せず、操作要求として扱う
- execution:precheck、risk、duplicate gateを通して実行する
OnChartEventは、クリックイベントを受ける入口です。そこから直接発注や決済へ進むのではなく、UI requestを作り、別のexecution層で安全確認してから処理する構成が安全です。
完成EAの中核ロジックを公開しなくても、パネルUI、Object命名、OnChartEvent、UI request、runtime stateの分離を理解しておくことで、パネルEAや裁量補助EAの設計・検証・不具合調査がしやすくなります。

