MT5のトレードパネル

# 目的
MetaTrader5でいい感じのトレードパネルを作る。

# 開発環境
+ Microsoft Visual Studio Community 2019
+ Version 16.11.9
+ Microsoft .NET Framework Version 4.8.09032

# データのやりとりの仕組み

[ここからの](https://www.mql5.com/ja/articles/5563) 引用です。

>![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531802/8c7134dc-ad51-fd03-f769-b48da007def5.png)

MQL側と.net側のコントローラ(DLL)を介して，
WinFormsとヨロシクやってくれるいい感じのやつです。

一つ問題があるとすると，コントローラで定義されているものしか，
WinFormsのコントローラとして使えないところでしょうか。

なので，DataGridViewみたいのは，コントローラ側（真ん中）で定義されていないので，
自分でDLLを改良する必要があります。

# C#側

こんな感じのレイアウトで行きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/531802/74a5e4b0-8297-056c-1e05-eaf492625c58.png)

ボタンを配置したり，TextBoxやらComboBoxを適当に配置するだけです。
イベントの割り当ては，コントローラ（DLL）で勝手にやってくれます。
余計なものもありますが，とりあえずコードを全部・・・。

``` c#
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace TradePanel
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }



        private void txtProfit_TextChanged(object sender, EventArgs e)
        {
            if (double.Parse(txtProfit.Text) > 0.0)
            {
                allSettlement.BackColor = Color.FromArgb(192, 192, 255);
            }
            else if (double.Parse(txtProfit.Text) < 0.0)
            {
                allSettlement.BackColor = Color.FromArgb(255, 128, 128);
            }
            else
            {
                allSettlement.BackColor = btnSelClose.BackColor;
            }

            txtProfit.Text = String.Format("{0:#,0}", double.Parse(txtProfit.Text));
        }

        private void txtBox_TextChanged(object sender, EventArgs e)
        {
            TextBox text = (TextBox)sender;
            text.Text = String.Format("{0:#,0}", double.Parse(text.Text));
        }

        private void checkBox1_CheckedChanged(object sender, EventArgs e)
        {
            CheckBox checkBox = (CheckBox)sender;
            if (checkBox.Checked)
            {
                this.TopMost = true;
            }
            else
            {
                this.TopMost = false;
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            CheckBox checkBox = checkBox1;
            if (checkBox.Checked)
            {
                this.TopMost = true;
            }
            else
            {
                this.TopMost = false;
            }
        }

        private void txtChangeBox_TextChanged(object sender, EventArgs e)
        {
            // DataGridView初期化（データクリア）
            //dataGridView1.Columns.Clear();
            //dataGridView1.Rows.Clear();


            //string[] items1 = cbxTicket.Items.OfType<string>().ToArray();
            //string[] items2 = cbxType.Items.OfType<string>().ToArray();
            //string[] items3 = cbxSymbol.Items.OfType<string>().ToArray();
            //string[] items4 = cbxOpenPrice.Items.OfType<string>().ToArray();
            //string[] items5 = cbxTP.Items.OfType<string>().ToArray();
            //string[] items6 = cbxSL.Items.OfType<string>().ToArray();
            //string[] items7 = cbxPrice.Items.OfType<string>().ToArray();
            //string[] items8 = cbxSwap.Items.OfType<string>().ToArray();
            //string[] items9 = cbxCommission.Items.OfType<string>().ToArray();
            //string[] items10 = cbxProfit.Items.OfType<string>().ToArray();

            //DataGridViewRow[] rows = new DataGridViewRow[items1.Length * 10];

            //for (int i = 0; i < items1.Length; i++)
            //{
            //    string[] data = new string[10];
            //    data[0] = items1[i];
            //    data[1] = items2[i];
            //    data[2] = items3[i];
            //    data[3] = items4[i];
            //    data[4] = items5[i];
            //    data[5] = items6[i];
            //    data[6] = items7[i];
            //    data[7] = items8[i];
            //    data[8] = items9[i];
            //    data[9] = items10[i];

            //    DataGridViewRow row = new DataGridViewRow();
            //    row.CreateCells(this.dataGridView1);
            //    row.SetValues(data);
            //    rows[i] = row;
            //}

            //this.dataGridView1.Rows.AddRange(rows);
        }

        private void textBox2_TextChanged(object sender, EventArgs e)
        {

        }

        private void numericUpDown1_ValueChanged(object sender, EventArgs e)
        {

        }
    }
}

```

# MQL側

続いてMQL側です。
MetaTrader5にしか対応してないです。

OnTickで，TickDataを受け取る度にイベントが発生し，
WinForms側のコントローラとつながるイメージです。

``` c
//+------------------------------------------------------------------+
//|                                              GuiMtController.mq5 |
//|                                   Copyright 2020, IINEbotXXX7963 |
//|                               https://twitter.com/IINEbotXXX7963 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, IINEbotXXX7963"
#property link      "https://twitter.com/IINEbotXXX7963"
#property version   "1.00"
//https://www.mql5.com/ja/articles/5563
//https://www.mql5.com/ja/articles/6549
//https://github.com/PublicMqlProjects/GuiControllerElementsDemo
//https://github.com/PublicMqlProjects/MtGuiController/blob/master/MtGuiController/IController.cs

#include <Trade\Trade.mqh>
string FormName = "Form1";
#import  "MtGuiController.dll"
input string assembly = "C:\\MT5\\TradePanel\\TradePanel\\bin\\Debug\\TradePanel.exe"; //実行ファイルの保存場所
input string dummy1 =""; //-------------------------------
input int msl = 10;//初期のsl　pips数
input int mtp = 20;//初期のtp　pips数

int gsl;
int gtp;

input double mcurrent_volume = 0.01; //初期のlot数
input string dummy2 =""; //-------------------------------
//-- 注文を実行するための取引モジュール
CTrade Trade;
double current_volume;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {

//--- タイマーを作成する
   EventSetMillisecondTimer(150);
   GuiController::ShowForm(assembly, FormName);

   current_volume = mcurrent_volume;

   GuiController::SendEvent("currentVolume", MtGuiController::GuiEventType::TextChange, 0, 0.0, DoubleToString(current_volume, 2));


   for(int i = 0; i < SymbolsTotal(true); i++)
     {
      GuiController::SendEvent("symbolCbx", MtGuiController::GuiEventType::AddItem, 0, 0, SymbolName(i, true));
     }


//---値をゲット
   double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
   double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   GuiController::SendEvent("askValue", MtGuiController::GuiEventType::TextChange, 0, 0.0, DoubleToString(ask, Digits()));
   GuiController::SendEvent("bidValue", MtGuiController::GuiEventType::TextChange, 0, 0.0, DoubleToString(bid, Digits()));

   GuiController::SendEvent("symbolCbx", MtGuiController::GuiEventType::TextChange, 0, 0.0, Symbol());

   gsl = msl;
   gtp = mtp;
   GuiController::SendEvent("txtSL", MtGuiController::GuiEventType::TextChange, 0, 0.0,IntegerToString(msl));
   GuiController::SendEvent("txtTP", MtGuiController::GuiEventType::TextChange, 0, 0.0,IntegerToString(mtp));

   GuiController::SendEvent("txtBalance", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE),0));//残高
   GuiController::SendEvent("txtCredi", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_CREDIT),0));//クレジット
   GuiController::SendEvent("txtEquity", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY),0));//有効証拠金
   GuiController::SendEvent("txtMargin", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN),0)); //必要証拠金
   GuiController::SendEvent("txtMarginFree", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_FREE),0)); //余剰証拠金
   GuiController::SendEvent("txtMarginLevel", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL),2) +"%"); //証拠金維持率
   GuiController::SendEvent("txtProfit", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_PROFIT),0));//全損益
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   GuiController::HideForm(assembly, FormName);
   EventKillTimer();

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   double ask = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
   double bid = SymbolInfoDouble(Symbol(), SYMBOL_BID);
   GuiController::SendEvent("askValue", MtGuiController::GuiEventType::TextChange, 0, 0.0, DoubleToString(ask, Digits()));
   GuiController::SendEvent("bidValue", MtGuiController::GuiEventType::TextChange, 0, 0.0, DoubleToString(bid, Digits()));


   GuiController::SendEvent("txtBalance", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_BALANCE),0));//残高
   GuiController::SendEvent("txtCredi", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_CREDIT),0));//クレジット
   GuiController::SendEvent("txtEquity", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_EQUITY),0));//有効証拠金
   GuiController::SendEvent("txtMargin", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN),0)); //必要証拠金
   GuiController::SendEvent("txtMarginFree", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_FREE),0)); //余剰証拠金
   GuiController::SendEvent("txtMarginLevel", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_MARGIN_LEVEL),2) +"%"); //証拠金維持率
   GuiController::SendEvent("txtProfit", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(AccountInfoDouble(ACCOUNT_PROFIT),0));//全損益



  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---






//--- タイマーで新しいイベントを取得する
   for(static int i = 0; i < GuiController::EventsTotal(); i++)
     {
      int id;
      string el_name;
      long lparam;
      double dparam;
      string sparam;
      GuiController::GetEvent(i, el_name, id, lparam, dparam, sparam);
      if(id ==  MtGuiController::GuiEventType::TextChange)
        {
         if(el_name == "currentVolume")
           {
            TrySetNewVolume(sparam);
           }

         if(el_name == "txtSL")
           {
            Print("SL->" + sparam);
            gsl = (int)StringToInteger(sparam);
           }
         if(el_name == "txtTP")
           {
            Print("TP->" + sparam);
            gtp = (int)StringToInteger(sparam);
           }
        }
      else
         if(id ==  MtGuiController::GuiEventType::ScrollChange && el_name == "incrementVol")
            OnIncrementVolume(lparam, dparam, sparam);
         else
            if(id ==  MtGuiController::GuiEventType::ClickOnElement)
               TryTradeOnClick(el_name);
            else
               if(id ==  MtGuiController::GuiEventType::ComboBoxChange && el_name == "symbolCbx")
                 {
                  ChartSetSymbolPeriod(0,sparam,0);
                 }

     }

   double totalPips = 0.0;
   int pt = PositionsTotal();
   for(int j = 0; j < PositionsTotal(); j++)
     {
      string symbol=PositionGetSymbol(j); // Get the symbol name
      if(PositionSelect(symbol))
        {
         double  value = 0.0;
         int digits ;
         digits = (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS);
         double pips = 0.0;
         // 3桁・5桁のFXブローカーの場合
         if(digits == 3 || digits == 5)
           {
            pips =  MathPow(10, digits) / 10;
           }
         // 2桁・4桁のFXブローカーの場合
         if(digits == 2 || digits == 4)
           {
            pips =  MathPow(10, digits);
           }

         int positionType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         string str="";
         //---
         if(positionType==0)
           {
            str="buy";
            //POSITION_PRICE_CURRENT -> このポジションの現在価格
            //POSITION_PRICE_OPEN -> このポジションの価格
            value = PositionGetDouble(POSITION_PRICE_CURRENT) - PositionGetDouble(POSITION_PRICE_OPEN);

           }
         if(positionType==1)
           {
            str="sell";
            value = PositionGetDouble(POSITION_PRICE_OPEN) - PositionGetDouble(POSITION_PRICE_CURRENT);
           }

         totalPips += value * pips;
         //Print("TOTAL_PIPS-> " + DoubleToString(totalPips));

        }


     }


   GuiController::SendEvent("txtTotalPips", MtGuiController::GuiEventType::TextChange, 0, 0.0,DoubleToString(totalPips,1));//全損益
   
//   
//      datetime tm=TimeCurrent();
//   int position =PositionsTotal();
//
//   for(int p = 0; p < position; p++)
//     {
//      string pos_symbol = PositionGetSymbol(p); // Get the symbol name
//      int digits ;
//      digits = (int)SymbolInfoInteger(pos_symbol, SYMBOL_DIGITS);
//      if(PositionSelect(pos_symbol))
//        {
//
//
//         //GuiController::SendEvent("cbxTicket", MtGuiController::GuiEventType::AddItem, 0, 0, IntegerToString(PositionGetInteger(POSITION_IDENTIFIER)));
//         //GuiController::SendEvent("cbxType", MtGuiController::GuiEventType::AddItem, 0, 0, PositionTypeToString((ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE)));
//         //GuiController::SendEvent("cbxSymbol", MtGuiController::GuiEventType::AddItem, 0, 0, PositionGetString(POSITION_SYMBOL));
//         //GuiController::SendEvent("cbxOpenPrice", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits));
//         //GuiController::SendEvent("cbxTP", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_TP),digits));
//         //GuiController::SendEvent("cbxSL", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_SL),digits));
//         //GuiController::SendEvent("cbxPrice", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_PRICE_CURRENT),digits));
//         //GuiController::SendEvent("cbxSwap", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_SWAP),0));
//         //GuiController::SendEvent("cbxCommission", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_COMMISSION),0));
//         //GuiController::SendEvent("cbxProfit", MtGuiController::GuiEventType::AddItem, 0, 0, DoubleToString(PositionGetDouble(POSITION_PROFIT),0));
//        }
//     }

   //GuiController::SendEvent("txtChangeBox", MtGuiController::GuiEventType::TextChange, 0, 0.0,TimeToString(tm)+TimeToString(tm,TIME_SECONDS));


  }
//+------------------------------------------------------------------+
//| Trade function                                                   |
//+------------------------------------------------------------------+
void OnTrade()
  {
//---

  }
//+------------------------------------------------------------------+
//| TradeTransaction function                                        |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction& trans,
                        const MqlTradeRequest& request,
                        const MqlTradeResult& result)
  {
//---

  }
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
  {
//---

  }
//+------------------------------------------------------------------+
//| BookEvent function                                               |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
  {
//---

  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| 数量を検証する                                                   |
//+------------------------------------------------------------------+
double ValidateVolume(double n_vol)
  {
   double min_vol = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MIN);
   double max_vol = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_MAX);
//-- 下限を確認する
   if(n_vol < min_vol)
      return min_vol;
//-- 上限を確認する
   if(n_vol > max_vol)
      return max_vol;
//-- 数量を正規化する
   double vol_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
   double steps = MathRound(n_vol / vol_step);
   double corr_vol = NormalizeDouble(vol_step * steps, 2);
   return corr_vol;
  }
//+------------------------------------------------------------------+
//| 与えられたテキストからの新しい現在の数量を設定する                  |
//+------------------------------------------------------------------+
bool TrySetNewVolume(string nstr_vol)
  {
   double n_vol = StringToDouble(nstr_vol);
   current_volume = ValidateVolume(n_vol);
   string corr_vol = DoubleToString(current_volume, 2);
   GuiController::SendEvent("currentVolume", MtGuiController::GuiEventType::TextChange, 0, 0.0, corr_vol);
   return true;
  }
//+------------------------------------------------------------------+
//| 取引注文を実行する                                              |
//+------------------------------------------------------------------+
bool TryTradeOnClick(string el_name)
  {

//double tsl,ttp;

// 現在の通貨ペアの小数点以下の桁数を取得
   int digits ;
   digits = (int)SymbolInfoInteger(Symbol(), SYMBOL_DIGITS);
   double pips = 0.0;
// 3桁・5桁のFXブローカーの場合
   if(digits == 3 || digits == 5)
     {
      pips =  MathPow(10, digits) / 10;
     }
// 2桁・4桁のFXブローカーの場合
   if(digits == 2 || digits == 4)
     {
      pips =  MathPow(10, digits);
     }


   if(el_name == "btnBuy")
     {
      double dvalue = 0.0;
      double avalue = SymbolInfoDouble(Symbol(), SYMBOL_BID);
      double limitRate,stopRate;
      dvalue = SymbolInfoDouble(Symbol(), SYMBOL_ASK); //buy時基準
      limitRate = NormalizeDouble(dvalue + gtp * 1/pips, digits);        // リミット価格    を正規化
      stopRate  = NormalizeDouble(avalue - gsl * 1/pips, digits);         // ストップロス価格を正規化
      ////---
      //  if(avalue > stopRate)
      //      stopRate = avalue;

      //Print("OpenPrice-> " + dvalue + " SL-> " + stopRate + " TP-> "+ limitRate);
      if(gsl == 0.0 && gtp == 0.0)
        {
         return Trade.Buy(current_volume);
        }
      if(gsl == 0.0)
        {
         return Trade.Buy(current_volume,NULL,0,NULL,limitRate);
        }
      if(gtp == 0.0)
        {
         return Trade.Buy(current_volume,NULL,0,stopRate,NULL);
        }

      return Trade.Buy(current_volume,NULL,0,stopRate,limitRate);
     }
   if(el_name == "btnSell")
     {
      double dvalue = 0.0;
      double avalue = SymbolInfoDouble(Symbol(), SYMBOL_ASK);
      double limitRate,stopRate;
      dvalue = SymbolInfoDouble(Symbol(), SYMBOL_BID); //buy時基準
      limitRate = NormalizeDouble(dvalue - gtp * 1/pips, digits);        // リミット価格    を正規化
      stopRate  = NormalizeDouble(avalue + gsl * 1/pips, digits);         // ストップロス価格を正規化

      if(gsl == 0.0 && gtp == 0.0)
        {
         return Trade.Sell(current_volume);
        }
      if(gsl == 0.0)
        {
         return Trade.Sell(current_volume,NULL,0,NULL,limitRate);
        }
      if(gtp == 0.0)
        {
         return Trade.Sell(current_volume,NULL,0,stopRate,NULL);
        }

      return Trade.Sell(current_volume,NULL,0,stopRate,limitRate);
     }
   if(el_name == "allSettlement")
     {
      positionAllClose();
      return true;
     }
   if(el_name == "btnSelClose")
     {
      positionSelectClose();
      return true;
     }//
   return false;
  }

//+------------------------------------------------------------------+
//|        すべてのポジションを決済                                        |
//+------------------------------------------------------------------+
void positionAllClose()
  {
   CPositionInfo cpo;
   int position =PositionsTotal();
   for(int p = 0; p < position; p++)
     {
      string pos_symbol = PositionGetSymbol(p); // Get the symbol name
      if(PositionSelect(pos_symbol))
        {
         int ti = (int)PositionGetInteger(POSITION_IDENTIFIER);
         Print("pos_symbol:" + pos_symbol + " tiket:" + IntegerToString(ti));
         if(!Trade.PositionClose(ti,0))
           {
            Sleep(20);
            Trade.PositionClose(ti,0);
           }
        }


     }

   Sleep(20);

   position = PositionsTotal();
   if(position > 0)
     {
      positionAllClose();
     }
  }

//+------------------------------------------------------------------+
//|        現在表示されているシンボルのみ決済                               |
//+------------------------------------------------------------------+
void positionSelectClose()
  {
   int position =PositionsTotal();
   for(int p = 0; p < position; p++)
     {
      if(PositionSelect(_Symbol))
        {
         int ti = (int)PositionGetInteger(POSITION_IDENTIFIER);
         Trade.PositionClose(ti,0);
        }
     }
  }



//+------------------------------------------------------------------+
//| 現在の数量を増減する                                        |
//+------------------------------------------------------------------+
void OnIncrementVolume(long lparam, double dparam, string sparam)
  {
   double vol_step = 0.0;
//-- インクリメントプレスを検出する
   if(dparam > lparam)
      vol_step = (-1.0) * SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
//-- デクリメントプレスを検出する
   else
      if(dparam < lparam)
         vol_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
      //-- インクリメントプレスを再検出する
      else
         if(lparam == 0)
            vol_step = SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
         //-- デクリメントプレスを再検出する
         else
            vol_step = (-1.0) * SymbolInfoDouble(Symbol(), SYMBOL_VOLUME_STEP);
   double n_vol = current_volume + vol_step;
   current_volume = ValidateVolume(n_vol);
   string nstr_vol = DoubleToString(current_volume, 2);
   GuiController::SendEvent("currentVolume", MtGuiController::GuiEventType::TextChange, 0, 0.0, nstr_vol);
  }

//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
//| CONVERTING POSITION TYPE TO A STRING                             |
//+------------------------------------------------------------------+
string PositionTypeToString(int position_type)
  {
   string str="";
//---
   if(position_type==0) { str="buy";  }
   if(position_type==1) { str="sell"; }
//---
   return(str);
  }
//+------------------------------------------------------------------+

```

このMQL5をExpertsフォルダに配置して，
Librariesフォルダには，[ここ](https://www.mql5.com/ja/articles/5563)から落としてくるか，
[GitHub](https://github.com/PublicMqlProjects/MtGuiController)ページからソースを落としてビルドしてください！

# 完成品

完成品はこちらにあります！

https://note.com/invesrorx/n/nbd75f59bc3e4#zjReB

# REFERENCEs

https://www.mql5.com/ja/articles/5563

https://www.mql5.com/ja/articles/6549

https://github.com/PublicMqlProjects/MtGuiController/blob/master/MtGuiController/IController.cs

https://github.com/PublicMqlProjects/MtGuiController

# さいごに

カレンダー参加者募集してます！

https://qiita.com/advent-calendar/2022/mql

Have a good MQL Life!!!