MT5版のボタン操作で全決済するツールを作成する【MQLプログラミングの基礎】
1.決済用ボタン追加
この記事では、チャート上に設置したボタン操作で、保有している全てのポジションを決済するツールを作成します。
※この記事はMQL5の内容です。
ファイルは新規作成せず、以前の記事で作成した、ボタン操作でエントリーするEA「TradePanel.mq5」を流用します。
「TradePanel.mq5」を改修して機能を追加します。
ファイル「TradePanel.mq5」をMetaEditorで開き、OnInit関数内の下記の行
ButtonCreate(0, PREFIX + "Buy", 0, 80, 20, 80, 40, CORNER_LEFT_UPPER, "Buy", "Arial Black", 20, clrWhite, clrRed, clrNONE);
の下に次のコードを追記し、決済用の「Exit」ボタンを追加します。
ButtonCreate(0, PREFIX + "Exit", 0, 0, 60, 160, 40, CORNER_LEFT_UPPER, "Exit", "Arial Black", 20, clrBlack, clrGold, clrNONE);

2.ボタン戻しの回路を追加
OnTimer関数内の下記の行
static bool stateBuy = false, stateSell = false;
に変数stateExitを追加して次のようにします。
static bool stateBuy = false, stateSell = false, stateExit = false;
また、下記の行
stateSell = ObjectGetInteger(0, PREFIX + "Sell", OBJPROP_STATE);
の下に次のコードを追記します。
if (stateExit) ObjectSetInteger(0, PREFIX + "Exit", OBJPROP_STATE, false);
stateExit = ObjectGetInteger(0, PREFIX + "Exit", OBJPROP_STATE);
上記を追記することで、Exitボタンを押しても自動で戻るようになります。
3.決済処理用の関数を作成
決済用の関数を作成するために、MQLリファレンス内にある例文を利用します。
MetaEditorメニューの「ヘルプ」から「MQL5リファレンス」を開いて、「目次」タブを選択し、「標準的な定数、列挙と構造体」→「取引定数」→「取引操作の種類」を開きます。

下へスクロールし、「ポジションを決済する 取引操作TRADE_ACTION_DEALの例:」の内容を表示します。

プログラム最下部(Entry関数の下)に、上記の例のOnStart関数をコピーして貼り付けます。
――――― コピーして貼り付けするコード(ここから) ―――――
//+------------------------------------------------------------------+
//| 全てのポジションを決済 |
//+------------------------------------------------------------------+
void OnStart()
{
//--- 結果とリクエストの宣言
MqlTradeRequest request;
MqlTradeResult result;
int total=PositionsTotal(); // 保有ポジション数
//--- 全ての保有ポジションの取捨
for(int i=total-1; i>=0; i--)
{
//--- 注文のパラメータ
ulong position_ticket=PositionGetTicket(i); // ポジションチケット
string position_symbol=PositionGetString(POSITION_SYMBOL); // シンボル
int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // 小数点以下の桁数
ulong magic=PositionGetInteger(POSITION_MAGIC); // ポジションのMagicNumber
double volume=PositionGetDouble(POSITION_VOLUME); // ポジションボリューム
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションタイプ
//--- ポジション情報の出力
PrintFormat("#%I64u %s %s %.2f %s [%I64d]",
position_ticket,
position_symbol,
EnumToString(type),
volume,
DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
magic);
//--- MagicNumberが一致している場合
if(magic==EXPERT_MAGIC)
{
//--- リクエストと結果の値のゼロ化
ZeroMemory(request);
ZeroMemory(result);
//--- 操作パラメータの設定
request.action =TRADE_ACTION_DEAL; // 取引操作タイプ
request.position =position_ticket; // ポジションチケット
request.symbol =position_symbol; // シンボル
request.volume =volume; // ポジションボリューム
request.deviation=5; // 価格からの許容偏差
request.magic =EXPERT_MAGIC; // ポジションのMagicNumber
//--- ポジションタイプによる注文タイプと価格の設定
if(type==POSITION_TYPE_BUY)
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID);
request.type =ORDER_TYPE_SELL;
}
else
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK);
request.type =ORDER_TYPE_BUY;
}
//--- 決済情報の出力
PrintFormat("Close #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
//--- リクエストの送信
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError()); // リクエストの送信に失敗した場合、エラーコードを出力
//--- 操作情報
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
//---
}
}
}
//+------------------------------------------------------------------+
――――― コピーして貼り付けするコード(ここまで) ―――――
関数名を変更します。下記の行の
void OnStart()
OnStartをExitへ変更します。
void Exit()
マジックナンバーの指定を変更します。
下記の行の
if(magic==EXPERT_MAGIC)
EXPERT_MAGICをパラメーターのMAGICへ変更します。
if(magic==MAGIC)
同様に、下記の行を
request.magic =EXPERT_MAGIC; // ポジションのMagicNumber
次のように変更します。
request.magic =MAGIC; // ポジションのMagicNumber
パラメーターの許容スリッページを反映するため、下記の行を
request.deviation=5; // 価格からの許容偏差
次のように変更します。
request.deviation=int(SLIP * 10); // 価格からの許容偏差
ボリューム実行ポリシー(request.type_filling)を指定するために、関数内の先頭にある下記の行の下へ
void Exit()
{
次のコードを追記して変数fillingを定義します。
ENUM_ORDER_TYPE_FILLING filling;
long mode = SymbolInfoInteger(NULL, SYMBOL_FILLING_MODE);
if ((mode & SYMBOL_FILLING_IOC) != 0) filling = ORDER_FILLING_IOC;
else if ((mode & SYMBOL_FILLING_FOK) != 0) filling = ORDER_FILLING_FOK;
else filling = ORDER_FILLING_RETURN;
注文リクエストへ実行ポリシーを指定するため、下記の行の下へ
request.deviation=int(SLIP * 10); // 価格からの許容偏差
次のコードを追記します。
request.type_filling = filling; // 注文充填
決済時に音を鳴らすため、下記の行の下へ
PrintFormat("OrderSend error %d",GetLastError()); // リクエストの送信に失敗した場合、エラーコードを出力
次のコードを追記します。
else PlaySound("ok.wav");
上記のExit関数で実行されている処理のおおまかな流れは、下記の通りです。
- ① for文で全ての保有ポジションの情報を取得
- ② マジックナンバーが一致しているポジションのみに処理を実行
- ③ ポジションのタイプ(売買方向)に合わせて、反対の売買を実行し、ポジションを決済(買いポジションの場合、売り取引を送信して決済する)
4.ボタン操作で決済
Exitボタンクリック時に、Exit関数を実行させるため、OnChartEvent関数の「if (id == CHARTEVENT_OBJECT_CLICK) { }」内の下記コード(売りエントリーのif文)
Entry(ORDER_TYPE_SELL, LOT, price, sl, tp, int(SLIP * 10), MAGIC, COMMENT);
}
の下へ次のコードを追記します。
if (sparam == PREFIX + "Exit") {
Exit();
}
上記までの改修で今回の作業は完了です。
コンパイル後、「Sell」「Buy」ボタンを押すとポジションを持ち、「Exit」ボタンを押すと全決済されることが確認できます。
5.ソースコード
今回、作成したソースコードは下記の通りです。
//+------------------------------------------------------------------+
//| TradePanel.mq5 |
//| Copyright 2025, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#define PREFIX MQLInfoString(MQL_PROGRAM_NAME) + "_"
input int MAGIC = 1; // マジックナンバー
input double LOT = 0.1; // ロット
input double TP = 50; // TP [pips]
input double SL = 50; // SL [pips]
input double SLIP = 1; // 許容スリッページ [pips]
input string COMMENT = ""; // コメント
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
ButtonCreate(0, PREFIX + "Sell", 0, 0, 20, 80, 40, CORNER_LEFT_UPPER, "Sell", "Arial Black", 20, clrWhite, clrDodgerBlue, clrNONE);
ButtonCreate(0, PREFIX + "Buy", 0, 80, 20, 80, 40, CORNER_LEFT_UPPER, "Buy", "Arial Black", 20, clrWhite, clrRed, clrNONE);
ButtonCreate(0, PREFIX + "Exit", 0, 0, 60, 160, 40, CORNER_LEFT_UPPER, "Exit", "Arial Black", 20, clrBlack, clrGold, clrNONE);
//--- create timer
EventSetMillisecondTimer(100);
//---
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
ObjectsDeleteAll(0, PREFIX);
//--- destroy timer
EventKillTimer();
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
//| Timer function |
//+------------------------------------------------------------------+
void OnTimer()
{
//---
static bool stateBuy = false, stateSell = false, stateExit = false;
if (stateBuy) ObjectSetInteger(0, PREFIX + "Buy", OBJPROP_STATE, false);
stateBuy = ObjectGetInteger(0, PREFIX + "Buy", OBJPROP_STATE);
if (stateSell) ObjectSetInteger(0, PREFIX + "Sell", OBJPROP_STATE, false);
stateSell = ObjectGetInteger(0, PREFIX + "Sell", OBJPROP_STATE);
if (stateExit) ObjectSetInteger(0, PREFIX + "Exit", OBJPROP_STATE, false);
stateExit = ObjectGetInteger(0, PREFIX + "Exit", OBJPROP_STATE);
ChartRedraw();
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int32_t id,
const long &lparam,
const double &dparam,
const string &sparam)
{
if (id == CHARTEVENT_OBJECT_CLICK) {
if (sparam == PREFIX + "Buy") {
double price = SymbolInfoDouble(NULL, SYMBOL_ASK);
double sl = NormalizeDouble(price - SL * _Point * 10, _Digits);
double tp = NormalizeDouble(price + TP * _Point * 10, _Digits);
Entry(ORDER_TYPE_BUY, LOT, price, sl, tp, int(SLIP * 10), MAGIC, COMMENT);
}
if (sparam == PREFIX + "Sell") {
double price = SymbolInfoDouble(NULL, SYMBOL_BID);
double sl = NormalizeDouble(price + SL * _Point * 10, _Digits);
double tp = NormalizeDouble(price - TP * _Point * 10, _Digits);
Entry(ORDER_TYPE_SELL, LOT, price, sl, tp, int(SLIP * 10), MAGIC, COMMENT);
}
if (sparam == PREFIX + "Exit") {
Exit();
}
}
}
//+------------------------------------------------------------------+
//| ボタンを作成する |
//+------------------------------------------------------------------+
bool ButtonCreate(const long chart_ID=0, // チャート識別子
const string name="Button", // ボタン名
const int sub_window=0, // サブウィンドウ番号
const int x=0, // X 座標
const int y=0, // Y 座標
const int width=50, // ボタンの幅
const int height=18, // ボタンの高さ
const ENUM_BASE_CORNER corner=CORNER_LEFT_UPPER, // アンカーに使用されるチャートのコーナー
const string text="Button", // テキスト
const string font="Arial", // フォント
const int font_size=10, // フォントサイズ
const color clr=clrBlack, // テキストの色
const color back_clr=C'236,233,216', // 背景色
const color border_clr=clrNONE, // 境界線の色
const bool state=false, // 押される/放される
const bool back=false, // 背景で表示する
const bool selection=false, // 強調表示して移動
const bool hidden=true, // オブジェクトリストに隠す
const long z_order=0) // マウスクリックの優先順位
{
//--- エラー値をリセットする
ResetLastError();
//--- ボタンを作成する
if(!ObjectCreate(chart_ID,name,OBJ_BUTTON,sub_window,0,0))
{
Print(__FUNCTION__,
": failed to create the button! Error code = ",GetLastError());
return(false);
}
//--- ボタン座標を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_XDISTANCE,x);
ObjectSetInteger(chart_ID,name,OBJPROP_YDISTANCE,y);
//--- ボタンサイズを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_XSIZE,width);
ObjectSetInteger(chart_ID,name,OBJPROP_YSIZE,height);
//--- ポイント座標が相対的に定義されているチャートのコーナーを設定
ObjectSetInteger(chart_ID,name,OBJPROP_CORNER,corner);
//--- テキストを設定する
ObjectSetString(chart_ID,name,OBJPROP_TEXT,text);
//--- テキストフォントを設定する
ObjectSetString(chart_ID,name,OBJPROP_FONT,font);
//--- フォントサイズを設定する
ObjectSetInteger(chart_ID,name,OBJPROP_FONTSIZE,font_size);
//--- テキストの色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_COLOR,clr);
//--- 背景色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_BGCOLOR,back_clr);
//--- 境界線の色を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_BORDER_COLOR,border_clr);
//--- 前景(false)または背景(true)に表示
ObjectSetInteger(chart_ID,name,OBJPROP_BACK,back);
//--- ボタンの状態を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_STATE,state);
//--- マウスでのボタンを移動させるモードを有効(true)か無効(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTABLE,selection);
ObjectSetInteger(chart_ID,name,OBJPROP_SELECTED,selection);
//--- オブジェクトリストのグラフィックオブジェクトを非表示(true)か表示(false)にする
ObjectSetInteger(chart_ID,name,OBJPROP_HIDDEN,hidden);
//--- チャートのマウスクリックのイベントを受信するための優先順位を設定する
ObjectSetInteger(chart_ID,name,OBJPROP_ZORDER,z_order);
//--- 実行成功
return(true);
}
//+------------------------------------------------------------------+
//| エントリー関数 |
//+------------------------------------------------------------------+
void Entry(ENUM_ORDER_TYPE type, double lot, double price, double sl, double tp, int slip, int magic, string comment)
{
ENUM_ORDER_TYPE_FILLING filling;
long mode = SymbolInfoInteger(NULL, SYMBOL_FILLING_MODE);
if ((mode & SYMBOL_FILLING_IOC) != 0) filling = ORDER_FILLING_IOC;
else if ((mode & SYMBOL_FILLING_FOK) != 0) filling = ORDER_FILLING_FOK;
else filling = ORDER_FILLING_RETURN;
//--- リクエストと結果の宣言と初期化
MqlTradeRequest request = {};
MqlTradeResult result = {};
//--- リクエストのパラメータ
request.action = TRADE_ACTION_DEAL; // 取引操作タイプ
request.symbol = Symbol(); // シンボル
request.volume = lot; // ロットのボリューム
request.type = type; // 注文タイプ
request.price = price; // 発注価格
request.sl = sl; // SL (指定する為に行を追加)
request.tp = tp; // TP (指定する為に行を追加)
request.deviation = slip; // 価格からの許容偏差
request.type_filling = filling; // 注文充填
request.magic = magic; // 注文のMagicNumber
//--- リクエストの送信
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError()); // リクエストの送信が失敗した場合、エラーコードを出力する
else PlaySound("ok.wav");
}
//+------------------------------------------------------------------+
//| 全てのポジションを決済 |
//+------------------------------------------------------------------+
void Exit()
{
ENUM_ORDER_TYPE_FILLING filling;
long mode = SymbolInfoInteger(NULL, SYMBOL_FILLING_MODE);
if ((mode & SYMBOL_FILLING_IOC) != 0) filling = ORDER_FILLING_IOC;
else if ((mode & SYMBOL_FILLING_FOK) != 0) filling = ORDER_FILLING_FOK;
else filling = ORDER_FILLING_RETURN;
//--- 結果とリクエストの宣言
MqlTradeRequest request;
MqlTradeResult result;
int total=PositionsTotal(); // 保有ポジション数
//--- 全ての保有ポジションの取捨
for(int i=total-1; i>=0; i--)
{
//--- 注文のパラメータ
ulong position_ticket=PositionGetTicket(i); // ポジションチケット
string position_symbol=PositionGetString(POSITION_SYMBOL); // シンボル
int digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS); // 小数点以下の桁数
ulong magic=PositionGetInteger(POSITION_MAGIC); // ポジションのMagicNumber
double volume=PositionGetDouble(POSITION_VOLUME); // ポジションボリューム
ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE); // ポジションタイプ
//--- ポジション情報の出力
PrintFormat("#%I64u %s %s %.2f %s [%I64d]",
position_ticket,
position_symbol,
EnumToString(type),
volume,
DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
magic);
//--- MagicNumberが一致している場合
if(magic==MAGIC)
{
//--- リクエストと結果の値のゼロ化
ZeroMemory(request);
ZeroMemory(result);
//--- 操作パラメータの設定
request.action =TRADE_ACTION_DEAL; // 取引操作タイプ
request.position =position_ticket; // ポジションチケット
request.symbol =position_symbol; // シンボル
request.volume =volume; // ポジションボリューム
request.deviation=int(SLIP * 10); // 価格からの許容偏差
request.type_filling = filling; // 注文充填
request.magic =MAGIC; // ポジションのMagicNumber
//--- ポジションタイプによる注文タイプと価格の設定
if(type==POSITION_TYPE_BUY)
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_BID);
request.type =ORDER_TYPE_SELL;
}
else
{
request.price=SymbolInfoDouble(position_symbol,SYMBOL_ASK);
request.type =ORDER_TYPE_BUY;
}
//--- 決済情報の出力
PrintFormat("Close #%I64d %s %s",position_ticket,position_symbol,EnumToString(type));
//--- リクエストの送信
if(!OrderSend(request,result))
PrintFormat("OrderSend error %d",GetLastError()); // リクエストの送信に失敗した場合、エラーコードを出力
else PlaySound("ok.wav");
//--- 操作情報
PrintFormat("retcode=%u deal=%I64u order=%I64u",result.retcode,result.deal,result.order);
//---
}
}
}
//+------------------------------------------------------------------+
本記事の監修者・HT FX
2013年にFXを開始し、その後専業トレーダーへ。2014年からMT4/MT5のカスタムインジケーターの開発に取り組む。ブログでは100本を超えるインジケーターを無料公開。投資スタイルは自作の秒足インジケーターを利用したスキャルピング。
EA(自動売買)を学びたい方へオススメコンテンツ

OANDAではEA(自動売買)を稼働するプラットフォームMT4/MT5の基本的な使い方について、画像や動画付きで詳しく解説しています。MT4/MT5のインストールからEAの設定方法までを詳しく解説しているので、初心者の方でもスムーズにEA運用を始めることが可能です。またOANDAの口座をお持ちであれば、独自開発したオリジナルインジケーターを無料で利用することもできます。EA運用をお考えであれば、ぜひ口座開設をご検討ください。
本ホームページに掲載されている事項は、投資判断の参考となる情報の提供を目的としたものであり、投資の勧誘を目的としたものではありません。投資方針、投資タイミング等は、ご自身の責任において判断してください。本サービスの情報に基づいて行った取引のいかなる損失についても、当社は一切の責を負いかねますのでご了承ください。また、当社は、当該情報の正確性および完全性を保証または約束するものでなく、今後、予告なしに内容を変更または廃止する場合があります。なお、当該情報の欠落・誤謬等につきましてもその責を負いかねますのでご了承ください。