こんにちは、潤奈です( ゚Д゚)!
前回の記事では、1つのチャートから複数の通貨ペアを監視・取引できる「マルチカレンシーEA」の仕組みと書き方を解説しました。
EA開発の基本ロジックをマスターしてくると、次に欲しくなるのが「チャート上から手動でワンクリック決済したい」「EAの自動売買モードをボタンで一時停止させたい」といった、視覚的・直感的に操作できるコントロール機能です。
MQL5(MT5)では、チャート上にボタンやテキスト入力欄などの「グラフィカルオブジェクト」を簡単に配置できます。さらに、それらがクリックされたことをプログラムで検知する仕組み(イベント処理)も標準で用意されています。
今回は、最も基本かつ実用的な「ワンクリックでポジションを全決済するボタン」をチャート上に配置するEAの作り方を分かりやすく解説します!
1. MQL5のオブジェクト作成とイベント処理の基本
チャート上にボタンを置き、クリックした際に処理を実行するためには、MQL5の以下の2つの仕組みを理解する必要があります。
① オブジェクトの作成(ObjectCreate)
MQL5では、チャート上に描画されるボタン、テキスト、ライン、四角形などをすべて「オブジェクト」と呼びます。
ボタンを作成するには、ObjectCreate() 関数にオブジェクトタイプとして OBJ_BUTTON を指定します。
作成したボタンは、サイズ、位置(X/Y座標)、背景色、表示する文字などをプロパティ設定関数(ObjectSetInteger() や ObjectSetString())を使って細かく装飾していきます。
② イベントハンドラ(OnChartEvent)
チャート上で「マウスがクリックされた」「ボタンオブジェクトが押された」「キーボードが押された」などのイベントが発生したとき、MT5が自動的に呼び出す特別な関数が OnChartEvent() です。
|
1 2 3 4 5 6 7 |
void OnChartEvent(const int id, // イベントID(種類) const long& lparam, // イベントに伴う数値データ const double& dparam, // イベントに伴う浮動小数点データ const string& sparam) // イベントが発生したオブジェクトの名前 { // ここにクリック時の処理を書く } |
ボタンをクリックした際は、id に CHARTEVENT_OBJECT_CLICK(オブジェクトクリックイベント)が渡され、sparam にクリックされたオブジェクトの名前(例: "CloseAllButton") が文字列として渡されます。
これを利用して、「もしクリックされたのが決済ボタンなら、決済処理を実行する」という分岐を作ります。
2. ボタンを配置・処理する3つのステップ
実践的で安全なコードにするための具体的な手順は以下の3ステップです。
ステップ①:OnInit() 内でボタンを作成して装飾する
EA起動時にボタンを生成し、見やすい位置(例: チャートの右上)に配置します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int OnInit() { string btnName = "CloseAllButton"; // ボタンの作成 (チャートID「0」は現在のチャートを指します) ObjectCreate(0, btnName, OBJ_BUTTON, 0, 0, 0); // ボタンのプロパティ設定 ObjectSetInteger(0, btnName, OBJPROP_XDISTANCE, 150); // 右端からの距離(150pxで右側価格スケールとの重なりを防ぐ) ObjectSetInteger(0, btnName, OBJPROP_YDISTANCE, 50); // 上端からの距離(50pxで右上のEA名表示との重なりを防ぐ) ObjectSetInteger(0, btnName, OBJPROP_XSIZE, 100); // ボタンの横幅 ObjectSetInteger(0, btnName, OBJPROP_YSIZE, 30); // ボタンの高さ ObjectSetInteger(0, btnName, OBJPROP_CORNER, CORNER_RIGHT_UPPER); // 基点を右上にする ObjectSetString(0, btnName, OBJPROP_TEXT, "全決済 (Close)"); // ボタンの文字 ObjectSetInteger(0, btnName, OBJPROP_COLOR, clrWhite); // 文字色 ObjectSetInteger(0, btnName, OBJPROP_BGCOLOR, clrRed); // 背景色(赤) ObjectSetInteger(0, btnName, OBJPROP_SELECTABLE, false); // マウスで選択不可にする return(INIT_SUCCEEDED); } |
ステップ②:OnChartEvent() 内でクリックを検知して処理する
ボタンがクリックされたことを検知し、実際の売買ロジック(全決済など)を呼び出します。
このとき、クリックされたボタンは「凹んだ状態(State = true)」になります。そのまま放置すると見た目が不自然なため、「処理完了後にプログラム側でボタンを凸状態(State = false)に戻す」という処理を入れるのが、親切で安全なUI設計のコツです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { // オブジェクトがクリックされたイベントかつ、名前が決済ボタンと一致するかチェック if(id == CHARTEVENT_OBJECT_CLICK && sparam == "CloseAllButton") { Print("全決済ボタンがクリックされました。"); // 実際の決済処理をここで呼び出す CloseAllCurrentSymbolPositions(); // ボタンの凹み状態(ステート)を自動で元(凸状態)に戻す ObjectSetInteger(0, "CloseAllButton", OBJPROP_STATE, false); ChartRedraw(); // チャートの再描画をしてビジュアルを反映させる } } |
ステップ③:OnDeinit() 内でオブジェクトを削除する
EAをチャートから外した際、作成したボタンオブジェクトがチャート上にそのまま残ってしまわないよう、終了時に必ず削除します。
|
1 2 3 4 5 |
void OnDeinit(const int reason) { // 作成したボタンを削除する ObjectDelete(0, "CloseAllButton"); } |
3. コピペで動く!「ワンクリック全決済ボタン」EA
それでは、実際の挙動を確認するためのサンプルコードを紹介します。
このEAをチャートにセットすると、右上に赤色の「Close All」ボタンが表示され、クリックすると現在の通貨ペアのポジションをすべて決済してくれます。
前回のマルチカレンシーEAでも使用した、無駄のない洗練されたポジション選択(PositionGetSymbol による自動選択)と決済ループを採用しています。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 |
//+------------------------------------------------------------------+ //| ButtonClickAll.mq5 | //| 潤奈FX | //+------------------------------------------------------------------+ #property copyright "潤奈FX" #property link "https://zyunafx.com" #property version "1.00" // --- 注文ライブラリの読み込み --- #include <Trade\Trade.mqh> CTrade trade; // --- 設定パラメータ --- input group "--- 取引設定 ---" input int MagicNumber = 444444; // マジックナンバー input int Slippage = 100; // 許容スリッページ (ポイント) // オブジェクト名の定義 #define BUTTON_NAME "CloseAllButton" //+------------------------------------------------------------------+ //| 初期化関数 | //+------------------------------------------------------------------+ int OnInit() { // CTradeの初期設定 trade.SetExpertMagicNumber(MagicNumber); trade.SetDeviationInPoints(Slippage); // チャート上にボタンオブジェクトを作成(「0」は現在のチャートを指します) if(ObjectCreate(0, BUTTON_NAME, OBJ_BUTTON, 0, 0, 0)) { // ボタンの各種パラメータを設定 ObjectSetInteger(0, BUTTON_NAME, OBJPROP_XDISTANCE, 150); // X軸位置 (右端から150px:価格スケール避け) ObjectSetInteger(0, BUTTON_NAME, OBJPROP_YDISTANCE, 50); // Y軸位置 (上端から50px:EA名表示避け) ObjectSetInteger(0, BUTTON_NAME, OBJPROP_XSIZE, 120); // 幅 ObjectSetInteger(0, BUTTON_NAME, OBJPROP_YSIZE, 35); // 高さ ObjectSetInteger(0, BUTTON_NAME, OBJPROP_CORNER, CORNER_RIGHT_UPPER); // 右上を基点にする ObjectSetString(0, BUTTON_NAME, OBJPROP_TEXT, "全決済 (Close)"); // ボタン上の文字 ObjectSetInteger(0, BUTTON_NAME, OBJPROP_COLOR, clrWhite); // 文字色 ObjectSetInteger(0, BUTTON_NAME, OBJPROP_BGCOLOR, clrRed); // 背景色 ObjectSetInteger(0, BUTTON_NAME, OBJPROP_SELECTABLE, false); // 選択不可にする(操作性向上) ChartRedraw(); // 再描画 } else { Print("ボタンオブジェクトの作成に失敗しました。"); return(INIT_FAILED); } Print("全決済ボタンEAが起動しました。"); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 後片付け関数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // チャートを汚さないよう、EA停止時に必ずボタンを削除する ObjectDelete(0, BUTTON_NAME); ChartRedraw(); Print("ボタンオブジェクトを削除しました。"); } //+------------------------------------------------------------------+ //| チック毎の処理関数(今回の自動売買ロジックは無し) | //+------------------------------------------------------------------+ void OnTick() { // 自動エントリー等のチック処理は今回行いません } //+------------------------------------------------------------------+ //| チャートイベント処理関数 | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long& lparam, const double& dparam, const string& sparam) { // ボタンのクリックイベントを検知 if(id == CHARTEVENT_OBJECT_CLICK && sparam == BUTTON_NAME) { Print("【UI操作】全決済ボタンがクリックされました。決済を実行します。"); // 全決済関数の実行 CloseAllCurrentSymbolPositions(); // ボタンを凹んだ状態(true)から凸状態(false)に戻して再描画する ObjectSetInteger(0, BUTTON_NAME, OBJPROP_STATE, false); ChartRedraw(); } } //+------------------------------------------------------------------+ //| 現在の通貨ペアのポジションを一括決済する関数 | //+------------------------------------------------------------------+ void CloseAllCurrentSymbolPositions() { int closedCount = 0; // 保有ポジションの逆順ループ処理 for(int i = PositionsTotal() - 1; i >= 0; i--) { // インデックスから通貨ペア名を取得(同時にポジションが内部選択されます) string positionSymbol = PositionGetSymbol(i); if(positionSymbol == _Symbol) { ulong ticket = PositionGetTicket(i); // 決済用のチケットを取得 if(ticket > 0) { PrintFormat("ポジション決済実行中... チケット: %I64u", ticket); if(trade.PositionClose(ticket)) { closedCount++; } } } } PrintFormat("全決済完了。合計 %d 個のポジションを決済しました。", closedCount); } //+------------------------------------------------------------------+ |
4. まとめ&次のステップ
今回は、EAに便利な機能を追加するための「チャート上のボタンオブジェクトの配置と、イベント処理の基本」を解説しました。
- チャート上のボタンや図形は「グラフィカルオブジェクト(OBJ_BUTTON)」として作成する。
- ボタンがクリックされたイベントは
OnChartEvent()内で検知する。 - クリックされたボタンは、処理完了後にプログラム側で凸状態(State = false)に戻す。
- EA停止時は、チャートにゴミを残さないよう
OnDeinit()内でオブジェクトを削除する。
チャート上にボタンを配置できると、手動の補助ツールとしても動く便利なEAを簡単に作れるようになります。
次回は、ボタンだけでなく、テキスト入力欄や背景パネルを組み合わせて、さらに整理された操作盤を作る「操作パネル(UIパネル)とテキスト入力フォームの作成方法」について解説します。パラメーター設定画面を開かずに、チャート上から直接ロット数などを変更できる便利なUI作りに挑戦しましょう!
今回のボタン配置コードで「ボタンが描画されない」「クリックしても決済が走らない」などのトラブルがあれば、YouTubeのコメント欄やXでお気軽にご連絡くださいね!


コメント