English Русский
preview
初心者からエキスパートへ:MQL5を使用したバックエンド操作モニター

初心者からエキスパートへ:MQL5を使用したバックエンド操作モニター

MetaTrader 5 |
21 0
Clemence Benjamin
Clemence Benjamin

構成内容

  1. はじめに
  2. 実装とコード
  3. テスト
  4. 結論
  5. 重要な学び
  6. 添付ファイル


はじめに

MetaEditor 5で取引ツールを正常にコンパイルできることは重要な節目ですが、それはあくまで出発点に過ぎません。コンパイルが成功したという事実は、コードが文法的に正しいことを示すだけであり、パフォーマンス、安定性、あるいは動作の正確性を保証するものではありません。本当の検証は、MetaTrader 5の実環境やストラテジーテスターでシステムを実行し、理論が実際の挙動としてどのように表れるかを確認する段階から始まります。

この段階で、開発者は共通の課題に直面します。自分でロジックを書いたにもかかわらず、リアルタイム環境下でEAがどのように振る舞うのかを完全には把握できないことがあるということです。プログラムはすべてのルールを機械的に実行するため、想定していなかった結果を生み出すこともあります。システムを改善し、最適化するには、単なる結果だけでなく、EAの内部で「何が」「いつ」「どこで」起きているのかを把握できる可視性が不可欠です。

組み込みログ機能の限界と本記事の解決策

MetaTrader 5には、主に以下の2つの監視手段が用意されています。

  • [エキスパート]タブ:稼働中のすべてのEAおよびインジケータが出力するログを表示
  • [操作ログ]タブ:ターミナルやサーバーに関するイベントを記録

これらは有用ではありますが、重大な制約があります。それは、すべてのEAが1つの[エキスパート]タブを共有している点です。ログ行にはEA名が含まれているものの、複数のシステムを同時に稼働させると出力がすぐに混在し、煩雑になってしまいます。複数のEAが動作している環境では、特定のツールに関するログだけを切り分けて確認することが難しくなり、デバッグ作業が遅れるだけでなく、結果に対する信頼性も低下します。

以下は、3つの異なるプログラムによるEAログが、同じ時系列で一覧表示されている例です。

2025.09.21 08:10:42.006 BEODemoEA (EURAUD,H4)   Abnormal termination
2025.09.21 08:20:15.056 Correlation Matrix 3D (EURAUD,M5)       Symbol 'EURUSD' is not synchronized
2025.09.21 08:20:40.862 Correlation Matrix 3D (EURAUD,M5)       Symbol 'EURGBP' is not synchronized
2025.09.21 08:20:44.065 Correlation Matrix 3D (EURAUD,M5)       Symbol 'EURCHF' is not synchronized
2025.09.21 08:20:44.067 Correlation Matrix 3D (EURAUD,M5)       Symbol 'EURJPY' is not synchronized
2025.09.21 08:20:44.078 Correlation Matrix 3D (EURAUD,M5)       Symbol 'GBPUSD' is not synchronized
2025.09.21 08:20:44.080 Correlation Matrix 3D (EURAUD,M5)       Symbol 'GBPCHF' is not synchronized
2025.09.21 08:20:44.082 Correlation Matrix 3D (EURAUD,M5)       Symbol 'GBPJPY' is not synchronized
2025.09.21 08:20:44.095 Correlation Matrix 3D (EURAUD,M5)       Symbol 'USDCHF' is not synchronized
2025.09.21 08:20:44.112 Correlation Matrix 3D (EURAUD,M5)       Symbol 'USDJPY' is not synchronized
2025.09.21 08:20:44.114 Correlation Matrix 3D (EURAUD,M5)       Symbol 'CHFJPY' is not synchronized
2025.09.21 08:20:44.114 Correlation Matrix 3D (EURAUD,M5)       Try again #0
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       Some symbols not ready to use:
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       EURUSD 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       EURGBP 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       EURCHF 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       EURJPY 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       GBPUSD 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       GBPCHF 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       GBPJPY 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       USDCHF 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       USDJPY 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       CHFJPY 
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       Error. Symbols not synchronized.
2025.09.21 08:20:44.125 Correlation Matrix 3D (EURAUD,M5)       Error. Rates data is not loaded.
2025.09.21 09:00:00.112 Institutional Trading Zones (EURAUD,M5) indicator | EURAUD,5 | Session Alert: Sydney End at 2025.09.21 07:00
2025.09.21 10:00:00.177 Institutional Trading Zones (EURAUD,M5) indicator | EURAUD,5 | Session Alert: London Start at 2025.09.21 08:00
2025.09.21 10:05:00.172 Institutional Trading Zones (EURAUD,M5) indicator | EURAUD,5 | Bearish overlap, look to sell

ここから、本記事におけるバックエンド操作(BEO: Backend Operations)クラスの解説が始まります。共有された[エキスパート]タブのみに依存するのではなく、チャート上に直接情報を表示し、整理できる、専用の監視およびログ記録システムを設計することが可能です。バックエンド操作に特化したクラスを構築することで、開発者は次のような利点を得られます。

  1. EAごとに分離された、見やすいデバッグ用インターフェース
  2. パフォーマンス指標や内部イベントをリアルタイムで可視化
  3. エラー、誤動作、実行フローの把握と特定が容易になる

本日の記事では、このようなクラスをどのように設計するかを詳しく解説します。これにより、デバッグ作業のワークフローを強化し、トレーダーおよび開発者の双方にとって、EAのバックエンドで何が起きているのかを正確に理解できる、信頼性の高いツールを提供することを目的とします。

コンセプトの検討

バックエンド操作(BEO)というコンセプトの実現性は、MetaTrader 5およびMQL5が、EA内部の監視や診断をおこなうために十分なシステムフックを提供しているかどうかにかかっています。幸いなことに、このプラットフォームには、口座状態、ターミナル環境、取引処理にアクセスするための豊富な関数群が用意されています。具体的には、環境情報を取得するためのAccountInfo*()やTerminalInfo*()、取引実行結果を扱うMqlTradeRequestおよびMqlTradeResultなどが挙げられます。これにより、構築するバックエンド層は、ターミナル自体が参照しているのと同じ低レベルの情報を常に利用でき、技術的に十分実現可能なコンセプトであることが保証されます。

もう一つの重要な要素は、これらの情報をどのように提示するかという点です。MQL5では、EAのログを表示する[エキスパート]タブ、ターミナルおよびサーバーメッセージを記録する[操作ログ]タブ、さらにComment()、ObjectCreate()、あるいはCCanvasのような高度なツールを用いたチャート上での可視化といった、複数の出力手段が提供されています。本記事で提案するカスタムクラスは、これらの仕組みを活用し、取引結果、エラーコード、診断メモを構造化された形で出力します。これにより、EAごとの内部動作を明確に区別できるようになり、複数のプログラムのログが混在してしまう[エキスパート]タブの制約を克服できます。

さらに、プラットフォームに備わっているエラー処理および履歴参照機能も、統合の実現性を支えています。GetLastError()や取引履歴へのアクセスを用いることで、本システム層はリアルタイムで発生する問題だけでなく、過去の取引状況に関する文脈も取得し、それらを開発者にとって分かりやすい形で表示または記録できます。これらを専用のバックエンドクラスとして整理することで、本コンセプトが実現可能であることを示すだけでなく、一貫したデバッグ、容易なアップグレード、そしてMetaTrader 5上での取引システムの透明性の高い監視を可能にします。

次のセクションでは、このアイデアをさらに発展させ、実装を段階的に詳しく見ていきます。BEOクラスのコード構造を確認しながら、重要なデバッグ情報をどのように取得し、整理し、表示しているのかを解説します。基礎が明確になった後は、チャート上でのテストを実行し、システムが取引チャートに直接リアルタイムのフィードバックを表示する様子を確認します。

最後に、完成したソリューション全体を共有し、開発者およびトレーダーが自身のワークフローに組み込めるようにします。これにより、理論、コード、そして実運用の間にあるギャップを埋めることを目指します。


実装とコード

バックエンド操作への取り組みは、明確さと効率性のバランスを重視した、体系的なアプローチから始まります。専用の監視クラスであるCBEOMonitorを設計することで、診断情報の追跡および表示という役割を、売買ロジックそのものから切り離すことができます。これによりデバッグ作業が簡素化されるとともに、同じ処理を何度も書き直すことなく、あらゆるEAに組み込める再利用可能な構成要素が導入されます。ここでの中心的な考え方はモジュール化であり、ひとつの強力なコードユニットを独立させ、多様なシステムに共通して活用できるようにすることです。

このコンセプトを具体的な形にするため、本記事では意図的に2つの段階に分けて実装をおこないました。まず、イベントの取得、情報の整形、そしてチャート上への整然とした描画といった中核機能をすべて備えたクラスそのものを構築しました。次に、そのクラスをデモ用のEAに統合し、実際の取引環境へどれほどスムーズに組み込めるかを示しました。この2段階の開発プロセスは効率性を強調するものです。すなわち、しっかりと作り込まれたひとつのツールが、より複雑なシステムへと容易に拡張できることを示しています。この基盤が整ったところで、次はコードを詳しく見ていき、各要素が実際にどのように機能しているのかを確認していきます。

手順1:CBEOMonitorクラス

インクルード内容とモニターが依存する要素

このモニターは、MQL5が提供するUIプリミティブおよび標準コンテナの上に構築されています。#include行では、ビットマップラベルの描画に使用するCanvas、小規模なメモリ内リングバッファとしてメッセージを保持するためのList、チャートオブジェクト関連の定数や補助機能を提供するObject.mqhとChartObject.mqh、そしてモニターのログ出力用ヘルパー関数で取引関連の補助機能を利用するためのTrade.mqhを読み込んでいます。また、列挙型では、メッセージの重要度レベルおよび表示モードを定義しています。これらは、フィルタリング、色分け、表示する行数の選択といった処理のあらゆる場面で使用されます。小さく明示的な列挙型を用いることで、APIの可読性が高まり、EAコード内でマジックナンバーを使用することを避けることができます。 

#include <Object.mqh>
#include <Canvas\Canvas.mqh>
#include <Arrays\List.mqh>
#include <Trade\Trade.mqh>
#include <ChartObjects\ChartObject.mqh>

// enums
enum BEO_Level { BEO_L_INFO=0, BEO_L_SUCCESS, BEO_L_WARNING, BEO_L_ERROR, BEO_L_TRADE, BEO_L_DEBUG };
enum BEO_DisplayMode { BEO_DM_COMPACT=0, BEO_DM_EXPANDED };

BEO_Item:ログに記録される情報の単位

各ログエントリは、BEO_Itemクラスによって表現されます。このクラスには、人間が読みやすいテキスト、重要度レベル、日時を示すdatetimeタイムスタンプ、パフォーマンス計測用のマイクロ秒精度のスタンプ、さらにメッセージがEAのどの箇所から発生したかを示す任意の発生元ラベルが格納されます。メッセージをオブジェクトとして保持することで、CListを用いた固定容量の循環バッファを実現しつつ、メモリ管理を簡潔に保つことができます。この小さな構造体は、画面表示および[エキスパート]ログへの出力の双方において基礎となる構成要素です。 

class BEO_Item : public CObject
{
public:
   string    text;
   BEO_Level level;
   datetime  time;
   ulong     micro;
   string    origin;

   BEO_Item() { text=""; level=BEO_L_INFO; time=0; micro=0; origin=""; }
   BEO_Item(string _text, BEO_Level _lvl, datetime _t, ulong _m, string _orig = "")
     { text=_text; level=_lvl; time=_t; micro=_m; origin=_orig; }
   void CopyFrom(const BEO_Item &src)
     { text=src.text; level=src.level; time=src.time; micro=src.micro; origin=src.origin; }
};

モニターの中核状態と配色設計:なぜ不透明色とソリッドテキストを採用するのか

このモニターは、独自のCCanvasに加えて、描画用のジオメトリ情報、表示状態、メッセージバッファ、そしてパフォーマンスカウンタを内部で管理しています。メインテキストには完全に不透明な色、具体的には白のソリッドテキストを採用し、キャプション、ハイライト、成功、警告、エラーメッセージには、それぞれ判別しやすい不透明なテクニカルカラーを使用しています。その目的は、どのようなチャート背景においても可読性を安定して確保し、色と意味の対応関係を一貫させることにあります。たとえば、エラーを示すm_errorを赤色に割り当てることで、視覚的に直感的な判別が可能になります。これらの色はcolor型のメンバ変数として保持され、各行を描画する際に適用されます。また、フォント名とフォントサイズをメンバとして管理し、フォントサイズについては制限範囲内に収めることで、CCanvas::FontSizeSet()に未対応の値が渡されるのを防いでいます。このため、Canvas APIを呼び出す前に、安全な値を返すCanvasFontSizeValue()を計算する設計としています。 

// color and font members (excerpt)
color m_text;       // solid white
color m_caption;    // header/caption color
color m_error;      // error messages
string m_font;
int    m_font_size;
int    m_transparent; // canvas transparency 0..255
// CanvasFontSizeValue() clamps m_font_size into safe range used by CCanvas::FontSizeSet

Create/Recreate/Destroy:即時に可視化されるプレースホルダーを伴うライフサイクル

キャンバスを作成すると同時に、小さなプレースホルダー(「BEO engine initializing...」)が即座に描画されます。これにより、EAをチャートに適用した瞬間に視覚的なフィードバックが得られ、アタッチや初期化時の問題をデバッグするうえで非常に有用です。CreateBitmapLabel()を使用してチャート上のビットマップオブジェクトを生成し、その後FontNameSet()、FontSizeSet()、TransparentLevelSet()によって描画設定をおこないます。RecreateCanvas()は、位置やサイズが変更された場合に、既存のキャンバスを安全に破棄したうえで再生成するための処理です。Destroy()は、キャンバスとメモリ上のメッセージバッファの両方をクリーンアップし、過去の失敗によって残されたフォールバック用ラベルがあれば、それらも確実に削除します。これらの手順は、MQL5公式ドキュメントで推奨されているリソース管理の原則に沿ったものです。すなわち、必要に応じてチャートオブジェクトやキャンバスリソースを作成、更新、破棄し、不要なリソースリークを防ぐという考え方を反映しています。 

bool CBEOMonitor::Create(string name,int x,int y,int w,int h)
{
   m_res_name = StringFormat("BEOMON_%s", name);
   if(!m_canvas.CreateBitmapLabel(m_res_name, x, y, w, h, COLOR_FORMAT_ARGB_RAW)) return(false);
   m_canvas.FontNameSet(m_font);
   m_canvas.FontSizeSet(CanvasFontSizeValue());                     // safe/clamped
   m_canvas.TransparentLevelSet((uchar)MathMax(0, MathMin(255, m_transparent)));
   // placeholder UI so chart shows something immediately
   m_canvas.Erase(m_bg);
   m_canvas.FillRectangle(2,2,w-4,24, ARGB(255,44,44,44));
   m_canvas.TextOut(20,7,"BEO: " + name, m_caption, ALIGN_RIGHT);
   m_canvas.Update(true);
   return(true);
}

ログ記録、バッファ制御、[エキスパート]出力:チャート表示とログの両面からのトレース

EAがLog(...)やInfo()、Error()といった簡易ラッパー関数を呼び出すと、モニターはBEO_Itemを生成し、CListバッファに追加します。同時にPrintFormat()を用いて[エキスパート]ログへメッセージを出力するため、同一の内容を標準の[エキスパート]タブ上でも確認できます。バッファはあらかじめ定めた容量を超えないように制御され、メモリ使用量が無制限に増加しない設計になっています。このように、チャート上のキャンバス表示と[エキスパート]ログへの出力を併用することで、即時性の高い視覚的な診断と、ターミナルログとして残る永続的なテキスト記録の両方を実現しています。 

void CBEOMonitor::Log(string text,BEO_Level lvl,string origin)
{
   if(lvl==BEO_L_DEBUG && !m_show_debug) return;
   BEO_Item it; it.text=text; it.level=lvl; it.time=TimeCurrent(); it.micro=_nowMicros(); it.origin=origin;
   _pushItem(it);
   PrintFormat("BEO[%s] %s%s", (lvl==BEO_L_INFO?"INFO": "..."), (origin!=""?("["+origin+"] "):""), text);
   Update();
}
void CBEOMonitor::_pushItem(const BEO_Item &it)
{
   BEO_Item *p = new BEO_Item; p.CopyFrom(it); m_buf.Add(p);
   while(m_buf.Total() > m_capacity) { BEO_Item *old=(BEO_Item*)m_buf.GetNodeAtIndex(0); if(old) delete old; m_buf.Delete(0); }
}

パフォーマンスタイミング:マイクロ秒単位の解像度で有用なプロファイリング

ティック処理の開始時にOnStartTick()を呼び出し、終了時にOnEndTick()を呼び出します。内部的にはGetMicrosecondCount()(MQL5の場合)を使用し、利用できない場合はGetTickCount()による粗い解像度にフォールバックします。モニターはローリング平均(m_tick_avg_ms)とカウンタを保持しており、チャート上の表示でティック処理がどれくらいコストがかかっているかを確認できます。この簡易プロファイリングは、新機能を追加した後にリグレッションを追跡する際に非常に有用です。もしティック処理時間が突然スパイクした場合でも、モニターが即座にそれを表示してくれます。 

void CBEOMonitor::OnStartTick(void) { m_last_tick_start = _nowMicros(); }
void CBEOMonitor::OnEndTick(void)
{
   if(m_last_tick_start==0) return;
   ulong endm=_nowMicros();
   double durms=(double)((endm>m_last_tick_start)?(endm-m_last_tick_start):0)/1000.0;
   m_tick_avg_ms=(m_tick_avg_ms*m_tick_count+durms)/(m_tick_count+1);
   m_tick_count++;
   m_last_tick_start=0;
   Update();
}
ulong CBEOMonitor::_nowMicros(void) const { #ifdef __MQL5__ return (ulong)GetMicrosecondCount(); #else return (ulong)GetTickCount()*1000; #endif }

描画とクリッピング:読みやすく、右揃えでオーバーフローしない出力

_draw()はキャンバスを構成します。境界線、キャプション、パフォーマンス行、EAバックエンドの概要、そして最近のメッセージ行です。各テキスト行は_clipLineToWidth()によってクリップされます(m_canvas.TextWidth()でピクセル幅を測定)。これにより、オーバーフローや表示されないテキストが発生しません。すべてのTextOut()呼び出しは、指定どおりALIGN_RIGHTを使用して右揃えで表示されます。メインのテキスト色は不透明な白で、キャプションやハイライトには専用の不透明カラーを使用します。描画後、m_canvas.Update(true)によってビットマップがチャートに反映され、BringToFrontInternal()がチャートオブジェクトのプロパティを再設定することで、キャンバスが他のオブジェクトの上に常に表示されるようにします。この方法により、異なるチャートサイズや解像度でも、チャート上の診断情報を一貫して読みやすく維持できます。 

void CBEOMonitor::_draw(void)
{
   if(!m_canvas_created) return;
   m_canvas.Erase(m_bg);
   m_canvas.Rectangle(1,1,m_w-2,m_h-2,m_border);
   m_canvas.FillRectangle(2,2,m_w-4,22, ARGB(255,44,44,44));
   m_canvas.TextOut(20,6,"BEO: " + m_name, m_caption, ALIGN_RIGHT);
   // perf
   int y=28;
   string perf = StringFormat("TickAvg: %.2f ms | Ticks: %d | Mem: %d KB", m_tick_avg_ms, (int)m_tick_count, (int)m_mem_kb);
   m_canvas.TextOut(20,y, _clipLineToWidth(perf, MathMax(20,m_w-40)), m_text, ALIGN_RIGHT);
   y += 18;
   // messages (most recent first)
   for(int i=m_buf.Total()-1; i>=0 && drawn<max_lines; i--)
   {
      BEO_Item *it=_getItemAt(i);
      string line = _clipLineToWidth(TimeToString(it.time,TIME_MINUTES|TIME_SECONDS) + " " + it.text, avail_px);
      m_canvas.TextOut(20,y,line,_colorFor(it.level),ALIGN_RIGHT);
      y+=14;
      drawn++;
   }
   m_canvas.Update(true);
   BringToFrontInternal();
}

手順2:CBEOMonitorをカスタムデモEAに統合する例 

EAヘッダとインクルード

EAの最上部では、取引実行とチャート上の表示の両方に必要なコアライブラリをすべてインクルードします。これには、すべての取引操作を管理するTrade.mqh、インタラクティブなチャートボタンを作成するControls\Button.mqh、そして構造化されたログと診断機能を備えた堅牢なモニタリングシステムを提供するBEOMonitor.mqhが含まれます。

その直後に、入力パラメータを宣言します。これにより、EAをチャートにアタッチする誰でもコードを変更せずに挙動を調整できます。入力パラメータは開発者が定義したデフォルト値で、EAはOnInit()でこれを読み込みます。コードのロジック自体は変更されません。名前はわかりやすく、デフォルト値は妥当なものにしてください。ピクセルや位置の入力(MonitorW/MonitorH)を使用する場合は、EAが実行時にこれらをbeo.Create(...)に渡し、モニターがキャンバスオブジェクトを作成する際に利用することを覚えておいてください。

#include <Trade\Trade.mqh>
#include <Controls\Button.mqh>
#include <BEOMonitor.mqh>

input string   DemoEAName        = "BEO Demo EA";
input bool     EnableMonitor     = true;
input int      MonitorX          = 10;
input int      MonitorY          = 60;
input int      MonitorW          = 400;
input int      MonitorH          = 220;
input bool     ShowDebugMessages = false;
input int      UpdateIntervalSec = 1;
input bool     AllowTrading      = false;
input double   DemoLotSize       = 0.01;
input double   DemoTakeProfit    = 30;
input double   DemoStopLoss      = 30;

グローバルオブジェクトとヘルパー

取引用のCTrade、モニタリング用のCBEOMonitor、そしてインタラクティブボタン用のCButtonというグローバルインスタンスを定義します。これらのオブジェクトはそれぞれ自身のライフサイクルを管理しますが、EA全体で参照されます。また、フォールバック用ラベルを作成するためのヘルパー関数も導入します。このラベルは、モニターキャンバスが初期化に失敗した場合の安全策として機能します。グラフィカルなモニターが表示されなくても、チャート上に即座にフィードバックを表示することで、システムが正常に動作していることを確認できます。

CTrade      trade;
CBEOMonitor beo;

CButton      m_buyButton;
CButton      m_sellButton;

static double g_prevBid = 0.0;
static double g_prevAsk = 0.0;
static datetime g_lastLogTime = 0;

string MakeFallbackName(const string base) { return ("BEO_FALLBACK_" + base); }

フォールバックラベル関数(CreateFallbackLabel、UpdateFallbackLabel、RemoveFallbackLabel)は、EAの処理を中断せずにチャート上でメッセージを動的に表示および更新できるようにします。これにより、EAの状態(例えば「初期化中」や「キャンバス作成に失敗」など)を常に把握できるため、テストやデバッグの際に非常に役立ちます。

チャート診断

モニタリングを補助するために、診断用関数PrintChartObjects()を実装しています。この関数はチャート上のすべてのオブジェクトを走査し、その名前、種類、コーナー、位置、可視性などのプロパティを出力します。これはリソースの競合をトラブルシューティングしたり、BEOキャンバスが正しく作成されているかを確認する際に重要です。この方法は「透明性」の原則に基づいており、チャート上に何が存在しているかを把握することで実行時の予期せぬ動作を防ぎ、テストの再現性を高めることができます。

void PrintChartObjects()
{
   int total = ObjectsTotal(0);
   PrintFormat("BEO Diagnostic: ObjectsTotal = %d", total);
   for(int i=0;i<total;i++)
   {
      string nm = ObjectName(0,i);
      long type   = ObjectGetInteger(0,nm,OBJPROP_TYPE);
      long corner = ObjectGetInteger(0,nm,OBJPROP_CORNER);
      long xdist  = ObjectGetInteger(0,nm,OBJPROP_XDISTANCE);
      long ydist  = ObjectGetInteger(0,nm,OBJPROP_YDISTANCE);
      bool hidden = (ObjectGetInteger(0,nm,OBJPROP_HIDDEN) != 0);
      PrintFormat("  [%d] name='%s' type=%d corner=%d x=%d y=%d hidden=%d",
                  i, nm, (int)type, (int)corner, (int)xdist, (int)ydist, hidden ? 1 : 0);
   }
}

初期化(OnInit)

OnInit関数では、モニターとクイック注文ボタンの両方に対して構造化されたセットアップをおこないます。モニタリングが有効な場合、プログラムはCBEOMonitorのキャンバスを作成しようとします。その後、作成が成功したかを確認し、成功していればデバッグを有効にし、起動メッセージをログに出力します。キャンバスの作成に失敗した場合でも、フォールバックラベルによりチャート上でのフィードバックが確保されます。

EAはまた、初期のBid価格とAsk価格を取得し、これを後続の市場変化を追跡する基準として使用します。このデータを用いて、手動での取引シミュレーションや実行を可能にするクイック注文ボタンを構築します。この仕組みにより、自動トリガーに依存せずに、取引ロジックをインタラクティブに検証する実用的な方法を提供します。さらに、モニタリング表示が常に最新の状態に保たれるよう、EAはキャンバスを定期的に更新するタイマーも設定します。

int OnInit()
{
   if(EnableMonitor)
   {
      bool created = beo.Create(DemoEAName, MonitorX, MonitorY, MonitorW, MonitorH);
      if(created && beo.IsCanvasCreated())
      {
         beo.EnableDebug(ShowDebugMessages);
         beo.Log("BEO engine initialized...", BEO_L_SUCCESS, "OnInit");
         RemoveFallbackLabel(DemoEAName);
      }
      else
      {
         CreateFallbackLabel(DemoEAName, MonitorX, MonitorY, 12, clrSilver);
      }
   }

   g_prevBid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   g_prevAsk = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(EnableQuickButtons)
   {
      // Create BUY and SELL buttons...
   }

   EventSetTimer(MathMax(1, UpdateIntervalSec));
   return(INIT_SUCCEEDED);
}

初期化解除(OnDeinit)

シャットダウン時、EAはモニターキャンバスとクイックボタンを適切に破棄するとともに、フォールバックラベルも削除します。パラメータが変更された場合は不要なログ出力を省略し、中断なくスムーズに更新できるようにします。このようにリソースを管理することで、チャート上に未使用のオブジェクトが残ったり、参照が宙に浮いた状態になることを防ぎます。この丁寧なクリーンアップは、自動売買システムにおけるライフサイクル管理のベストプラクティスを反映しています。

void OnDeinit(const int reason)
{
   if(EnableMonitor && reason != REASON_PARAMETERS)
   {
      beo.Log("Shutting down demo EA", BEO_L_INFO, "OnDeinit");
      beo.ClearHistory();
      beo.Destroy();
      RemoveFallbackLabel(DemoEAName);
   }

   m_buyButton.Destroy(reason);
   m_sellButton.Destroy(reason);
   EventKillTimer();
}

タイマー更新(OnTimer)

OnTimerイベントは定期的な更新を管理します。キャンバスが存在しない場合はモニターキャンバスを再作成し、フォールバックラベルを更新するとともに、モニター表示をリフレッシュします。さらに、30秒ごとにハートビートをログに記録し、メッセージ数、ティック処理性能、システムの健全性を把握できるようにします。この定期的な更新機構により、EAは一時的なチャートやリソースの問題に対しても堅牢に動作します。

void OnTimer()
{
   if(!EnableMonitor) return;

   if(!beo.IsCanvasCreated())
   {
      static int tries = 0;
      tries++;
      bool ok = beo.Create(DemoEAName, MonitorX, MonitorY, MonitorW, MonitorH);
      if(ok) { /* recovered canvas */ }
      else
      {
         string txt = StringFormat("BEO fallback: msgs=%d | TickAvg=%.3f ms", beo.MessagesCount(), beo.GetTickAvgMs());
         UpdateFallbackLabel(DemoEAName, txt, MonitorX, MonitorY, 11, clrWhite);
      }
   }
   else RemoveFallbackLabel(DemoEAName);

   beo.Update(true);

   if(TimeCurrent() - g_lastLogTime >= 30)
   {
      string summary = StringFormat("Msgs:%d | TickAvg: %.3f ms | LastMicros: %llu",
                                    beo.MessagesCount(), beo.GetTickAvgMs(), beo.GetLastMicros());
      beo.Log("Periodic heartbeat: " + summary, BEO_L_DEBUG, "OnTimer");
      g_lastLogTime = TimeCurrent();
   }
}

ティック処理(OnTick)

OnTick関数はEAのコアとなるリアクティブロジックです。市場の各ティックごとに、EAはモニターを更新し、BidおよびAskの変化を追跡し、関連する価格変動をログに記録します。EA内の簡単なデモ戦略では、重要な価格変動を記録し、AllowTradingが有効な場合には取引を実行することも可能です。ロジックをOnStartTickとOnEndTickに分割することで、モニターとのやり取りの境界を明確に保ち、モジュール性を強化するとともに可読性を向上させています。

void OnTick()
{
   if(EnableMonitor) beo.OnStartTick();

   double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID);
   double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK);

   if(EnableMonitor && (bid != g_prevBid || ask != g_prevAsk))
   {
      string txt = StringFormat("Bid: %.*f Ask: %.*f",
                                (int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS), bid,
                                (int)SymbolInfoInteger(_Symbol,SYMBOL_DIGITS), ask);
      beo.Info(txt, "OnTick");
      g_prevBid = bid; g_prevAsk = ask;
   }

   // Simple demo strategy: log and optionally trade on price movement
}

クイック注文ボタン

システムはユーザーの操作をOnChartEventとExecuteQuickOrderを通じて処理します。ボタンをクリックすると、AllowTradingフラグに応じてシミュレーション取引または実際の取引が実行されます。これにより、取引ロジックを安全にデモンストレーションしつつ、バックエンドの操作監視システムと完全に統合することができます。

void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      if(sparam == "BEO_BUY_BTN") ExecuteQuickOrder(ORDER_TYPE_BUY);
      else if(sparam == "BEO_SELL_BTN") ExecuteQuickOrder(ORDER_TYPE_SELL);
   }
}

void ExecuteQuickOrder(ENUM_ORDER_TYPE orderType)
{
   if(!AllowTrading) { /* simulate */ return; }

   MqlTradeRequest req; MqlTradeResult res;
   ZeroMemory(req); ZeroMemory(res);

   if(orderType == ORDER_TYPE_BUY) { /* set buy parameters */ }
   else { /* set sell parameters */ }

   if(!OrderSend(req, res)) beo.LogErrorDetails(...);
   else beo.LogTradeDetails(res, ..., "QuickButton");
}

このアプローチにより、CBEOMonitorの完全な統合が示されます。EAの主要なアクション(初期化、ティック更新、タイマーイベント、取引実行、ボタン操作)のすべてが構造化されたログに反映され、パフォーマンスデータを記録し、モニターキャンバスが表示できない場合でもフォールバック表示を可能にします。システムはモジュール化されており、可読性と堅牢性を備えているため、ライブトレードとテストの両方において明確で保守性の高い運用が可能です。



テスト

ターミナルでテストをおこなうには、EAとBEOMonitorクラスを含むヘッダファイルの両方が、エラーなく正常にコンパイルされている必要があります。MetaTrader 5ターミナルのナビゲーターの「Experts」セクションには、BEODemoEAが使用可能として表示されます。対象のチャートにドラッグして、デフォルト設定で初期化を許可してください。初期化が完了すると、システムは自動的にモニターキャンバスを作成し、クイック注文ボタンを設定し、受信するティックデータの処理を開始します。

チャート上では、コード実行の結果がリアルタイムで確認できます。キャンバスには受信ティックに応じたBidおよびAskの更新が表示され、初期化メッセージによってモニターとボタンが正しく作成されたことが確認できます。同時に、[エキスパート]タブのログでバックエンド側の確認もおこなえるため、表示されている情報がEAの内部動作と一致しているかを検証することができます。この直接的な可視化により、テストは単に機能を確認するだけでなく、インタラクティブにおこなうことができ、ライブマーケットデータ上でシステムの挙動を即座に把握できます。

EURUSDでのBEOテスト

図1:チャート上にEAを展開する

BEOテスト

図2:シミュレーション取引用のクイック注文ボタンを使用したバックエンドの操作表示

MetaTrader 5ターミナルエキスパートのログ

2025.09.23 12:49:41.142 BEODemoEA (USDCHF,H1)   BEOMonitor: Created canvas resource 'BEOMON_BEO Demo EA' at 10,60 size 600x220
2025.09.23 12:49:41.170 BEODemoEA (USDCHF,H1)   BEO Demo: beo.Create returned true
2025.09.23 12:49:41.170 BEODemoEA (USDCHF,H1)   BEO Demo: beo.IsCanvasCreated() = true
2025.09.23 12:49:41.170 BEODemoEA (USDCHF,H1)   BEO Demo: expected canvas name = 'BEOMON_BEO Demo EA'
2025.09.23 12:49:41.178 BEODemoEA (USDCHF,H1)   BEO Diagnostic: ObjectsTotal = 3
2025.09.23 12:49:41.179 BEODemoEA (USDCHF,H1)     [0] name='BEOMON_BEO Demo EA' type=106 corner=0 x=10 y=60 hidden=0
2025.09.23 12:49:41.179 BEODemoEA (USDCHF,H1)     [1] name='BEO_BUY_BTN' type=103 corner=0 x=10 y=300 hidden=1
2025.09.23 12:49:41.180 BEODemoEA (USDCHF,H1)     [2] name='BEO_SELL_BTN' type=103 corner=0 x=100 y=300 hidden=1
2025.09.23 12:49:41.196 BEODemoEA (USDCHF,H1)   BEO[OK] [OnInit] BEO engine initialized...
2025.09.23 12:49:41.228 BEODemoEA (USDCHF,H1)   BEO[INFO] [OnInit] Quick Order Buttons (CButton) created: BUY/SELL for ops testing
2025.09.23 12:49:59.941 BEODemoEA (USDCHF,H1)   BEO[INFO] [OnTick] Bid: 0.79537 Ask: 0.79551

上記の診断エントリから、キャンバスが意図した座標とサイズで初期化され、beo.Createやbeo.IsCanvasCreated()といった検証チェックがすべてtrueを返したことが確認できます。これは、カスタムモニタークラスとチャート環境との統合が安定していることを示しています。さらに、期待されるキャンバス名も正しく一致しており、リソースの適切な識別が保証されています。診断のサマリーでは、非表示のBUYおよびSELLクイック注文ボタンを含む関連オブジェクトも列挙されており、システムが主要表示コンポーネントを適切に管理し、補助コントロールも一貫して扱っていることが確認できます。

機能面では、初期化ログによりBEOエンジンが確実に動作状態に入り、クイック注文テスト用ボタンも意図通り生成されていることが示されています。この段階では非表示ですが、リアルタイムのOnTickフィードによって、モニターを通じて市場データを取得および描画できることが確認でき、BidおよびAsk価格がキャンバス上でライブにストリーミングされます。

これにより、概念が実証され、バックエンドのEAの活動をターミナルのテキストログに頼ることなく、専用のカスタム環境で可視化できることが示されました。基盤は堅牢ですが、今後の改善点としては、プレゼンテーション層の洗練、クイック注文コントロールとのインタラクションの向上、より複雑なEA操作を含む診断フィードバックの拡張が考えられます。この成果は有望な出発点であり、アーキテクチャの妥当性を検証するとともに、反復的な開発のための堅実なプラットフォームを提供します。



結論

BEOのコンセプトを実現することに成功しました。キャンバスはカスタマイズ可能なサイズで描画され、EAのバックエンド操作をリアルタイムで動的に表示できるようになっています。開発の過程でいくつかの課題にも直面しました。初期段階では、背景に溶け込む透明色を選択したためテキストの視認性が低くなっていましたが、その後、明瞭さを高めるために不透明で明るい色に変更しました。

また、テキストの配置も課題でした。最初の試みでは左端をはみ出してしまいましたが、ALIGN_RIGHTに切り替えることで、ワードプロセッサでは通常左揃えが期待されるにもかかわらず、チャート上で見やすく整った表示を実現できました。これらの修正により、チャート上の表示は機能的で視覚的にも一貫性があり、さらに重要なことに、静的ではなく、EAのティックごとのバックエンド活動がリアルタイムで表示されるようになりました。

この結果により、アイデアの妥当性が確認されましたが、あくまで基盤に過ぎません。EAに専用のログ空間を提供することで、混雑するターミナルの[エキスパート]タブから独立させるという重要な課題は解決しましたが、ターミナル自体がデバッグ用にログを簡単にコピーできる便利な機能を持つことも認識しています。現時点では、重要なバックエンド情報をチャート上で直接可視化できますが、今後は機能の拡張、ログデータのより詳細なカスタマイズ、高度なフィルタリング、あるいはキャンバスからのログのインタラクティブなコピーなどの改良が考えられます。この作業は堅実な基盤を築くものであり、成長の余地は十分にあります。この形で提示することで、プロジェクトの可能性を示すことができ、将来的な更新によってさらに大きく発展させることも可能です。

このアイデアをぜひ自分のプロジェクトで探求、実験、拡張してください。重要な学びをまとめた短い表と添付コードでこの議論を補完します。皆さんのコメントや貢献が、次のステップを形作る助けとなります。

重要な学び

学び説明
MQL5でのカスタムクラスの開発CBEOMonitorのような専用クラスを構築することで、複雑な機能を再利用可能なモジュールとしてカプセル化でき、取引システムの保守性と拡張性が向上します。
カスタムクラスと標準MQL5ライブラリクラスの統合ユーザー定義クラスとCTradeやCButtonといった標準ライブラリコンポーネントを組み合わせることで、MQL5がカスタム機能と信頼性の高い組み込み機能を柔軟に融合できることを示しています。
キャンバス統合カスタムキャンバスを使用することで、EAはチャート上にバックエンド操作を視覚的に表示でき、ターミナルのログウィンドウに依存せずに専用のモニタリングスペースを作成できます。
色と可視性の管理透明色ではなく適切な不透明色を選択することは、診断用テキストやデータの視認性を確保する上で重要です。これにより、異なるチャート背景でも情報が見やすくなります。
テキスト配置正確な配置により、表示テキストのはみ出しや誤配置を防ぐことができます。ALIGN_LEFT、ALIGN_RIGHTおよびチャートオフセットの挙動を理解することで、整った表示を維持できます。
フォールバックの仕組みキャンバス作成に失敗した場合にラベルをフォールバックとして実装することで、堅牢性を確保できます。これにより、高度なリソースが初期化できなくても、最低限の状態フィードバックが提供されます。
リアルタイム診断ティックデータ、スプレッドの変化、取引シグナルをチャート上に直接ログとして記録することで、EAはライブフィードバックループを作り、デバッグやパフォーマンスの検証を容易にします。

添付ファイル

ファイル名バージョン説明
BEOMonitor.mqh1.00EAバックエンド操作のキャンバス、ログ、視覚的な診断を管理するコア監視クラス。チャート上の描画、ログ記録、構造化された出力のための再利用可能なメソッドを提供します。
BEODemoEA.mq51.00CBEOMonitorを統合したデモ用EAで、カスタマイズ可能なコントロールを使用してライブログ記録、診断の視覚化、クイック注文テストを紹介します。

MetaQuotes Ltdにより英語から翻訳されました。
元の記事: https://www.mql5.com/en/articles/19649

添付されたファイル |
BEOMonitor.mqh (48.41 KB)
BEODemoEA.mq5 (27.26 KB)
EAのサンプル EAのサンプル
一般的なMACDを使ったEAを例として、MQL4開発の原則を紹介します。
MQL5での取引戦略の自動化(第35回):ブレーカーブロック取引システムの作成 MQL5での取引戦略の自動化(第35回):ブレーカーブロック取引システムの作成
本記事では、MQL5でブレーカーブロック取引システムを作成します。本システムは、レンジ相場を識別し、ブレイクアウトを検出、スイングポイントでブレーカーブロックを検証した上で、リスクパラメータを定義してリテスト取引を実行します。また、オーダーブロックおよびブレーカーブロックを動的なラベルと矢印で可視化し、自動売買やトレーリングストップにも対応しています。
エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法 エラー 146 (「トレードコンテキスト ビジー」) と、その対処方法
この記事では、MT4において複数のEAの衝突をさける方法を扱います。ターミナルの操作、MQL4の基本的な使い方がわかる人にとって、役に立つでしょう。
プライスアクション分析ツールキットの開発(第42回):ボタンロジックと統計レベルを用いたインタラクティブチャートの検証 プライスアクション分析ツールキットの開発(第42回):ボタンロジックと統計レベルを用いたインタラクティブチャートの検証
市場においてスピードと精度が重要である以上、分析ツールも市場と同じくらい賢くある必要があります。本記事では、ボタン操作に基づくエキスパートアドバイザー(EA)を紹介します。これは、価格データを瞬時に意味のある統計レベルに変換するインタラクティブなシステムです。ワンクリックで平均値、偏差、パーセンタイルなどを計算して表示し、複雑な分析をチャート上の明確なシグナルに変換します。価格が反発、押し戻し、または突破する可能性の高いゾーンをハイライトすることで、分析をより迅速かつ実用的にします。