1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【MQL4 : MT4】GUI で 全決済、個別決済 を実装した EA を作る。【Dialog】

Last updated at Posted at 2020-03-20

23/09/22追記
note購入者はDMして下されば続きが読めます!
https://note.com/iceseeds/n/nfdae2c5ac2ef

はじめに

ここでは、GUIで全決済、個別決済を実装します。
前回までの記事を理解しているのが前提です。
[【MQL4 : MT4】GUI で 売買機能を実装した EA を作る。③]
作成手順としては、以下の通りです。

  1. ComboBoxの作成
  2. 全決済、個別決済処理
  3. Event.mqhに処理を追加
    ※前回とは画面サイズを変えています。
    if( !AppWindow.Create( ChartID(), "SampleTitle", 0, 0, 0, 250, 100 ) )
                       ↓↓↓↓
    if( !AppWindow.Create( ChartID(), "SampleTitle", 0, 0, 0, 250, 120 ) )
    .
    ※ネーミングセンスはありません。なるだけ分かりやすくしているつもりです!
    いろいろと初心者な為、至らない部分もありますが、宜しくお願いします。
    フォルダ構造のアドバイスなどを頂けると助かります。
  • Experts/
    • Sample/
      • Plugin/        ←これから機能を追加していくフォルダを作りました。
        • ExitCurrency.mqh  ←今回のメインファイルです。
      • guiwindow.mq4
      • AppWindow.mqh
      • Event.mqh

実行結果

Screenshot_5.png
All Exitを選択し、Pushすると、仕掛けているポジションを全て決済します。
This Exitを選択し、Pushすると、Pushした通貨のポジションを全て決済します。
( この場合は、USDJPYのポジションを全て決済します )

全決済、個別決済機能

前回までが理解できていれば、GUI部分は簡単です。

AppWindow.mqh

AppWindow.mqh
#include <Controls\Dialog.mqh>
#include <Controls\Button.mqh>
#include <Controls\Edit.mqh>
#include <Controls\ComboBox.mqh>  // --- 1
class CPanelDialog : public CAppDialog
{
   public:
       CPanelDialog();
      ~CPanelDialog();
   
      /* create */
      virtual bool      Create( const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2 );
      /* chart event handler */
      virtual bool      OnEvent( const int id, const long &lparam, const double &dparam, const string &sparam );
      
      CEdit             m_editLots;
      CButton           m_btnBuy;
      CButton           m_btnSell;
      CButton           m_btnUp;
      CButton           m_btnDown;
      CComboBox         m_combCreate;
      CButton           m_btnComb;
      
   protected:
      bool              CreateEditLots();
      bool              CreateBtnBuy();
      bool              CreateBtnSell();
      bool              CreateBtnUp();
      bool              CreateBtnDown();
      bool              CreateCombCreate();
      bool              CreateBtnComb();
      
      void              OnClickBtnUp();
      void              OnClickBtnDown();
};
EVENT_MAP_BEGIN( CPanelDialog )
ON_EVENT( ON_CLICK, m_btnUp,     OnClickBtnUp )
ON_EVENT( ON_CLICK, m_btnDown,   OnClickBtnDown )
EVENT_MAP_END( CAppDialog )
CPanelDialog::CPanelDialog(){}
CPanelDialog::~CPanelDialog(){}
bool CPanelDialog::Create( const long chart, const string name, const int subwin, const int x1, const int y1, const int x2, const int y2 )
{
   if( !CAppDialog::Create( chart, name, subwin, x1, y1, x2, y2 ) )
      return false;
   
   if( !CreateEditLots() )    return false;
   if( !CreateBtnUp() )       return false;
   if( !CreateBtnDown() )     return false;
   if( !CreateBtnBuy() )      return false;
   if( !CreateBtnSell() )     return false;
   if( !CreateCombCreate() )  return false;
   if( !CreateBtnComb() )     return false;
   
   return true;
}
bool CPanelDialog::CreateEditLots()
{
   int widths = ClientAreaWidth() / 5;
   int x1 = widths;
   int y1 = 0;
   int x2 = widths * 4;
   int y2 = 20;
   
   if( !m_editLots.Create( m_chart_id, m_name + "Edit", m_subwin, x1, y1, x2, y2 ) ) return false;
   if( !m_editLots.ReadOnly( false ) ) return false;
   if( !Add( m_editLots ) ) return false;
   m_editLots.TextAlign( ALIGN_CENTER );
   m_editLots.Text( "0.10" );
   
   return true;
}
~
中略
~
bool CPanelDialog::CreateCombCreate()             // --- 2
{
   int widths = ClientAreaWidth() / 5;
   int x1 = 0;
   int y1 = ClientAreaHeight() - 20;
   int x2 = widths * 4;
   int y2 = ClientAreaHeight();
   
   if( !m_combCreate.Create( m_chart_id, m_name + "comboCreate", m_subwin, x1, y1, x2, y2 ) ) return false;
   m_combCreate.AddItem( "All Exit", 0 );
   m_combCreate.AddItem( "This Exit", 1 );
   
   if( !Add( m_combCreate ) ) return false;
   
   return true;
}
bool CPanelDialog::CreateBtnComb()
{
   int widths = ClientAreaWidth() / 5;
   int x1 = widths * 4;
   int y1 = ClientAreaHeight() - 20;
   int x2 = ClientAreaWidth();
   int y2 = ClientAreaHeight();
   
   if( !m_btnComb.Create( m_chart_id, m_name + "btnComb", m_subwin, x1, y1, x2, y2 ) ) return false;
   if( !m_btnComb.Text( "Push" ) ) return false;
   if( !Add( m_btnComb ) ) return false;
   
   return true;
}
/* Event Handle */
void CPanelDialog::OnClickBtnUp()
{
   m_btnUp.Pressed( false );
   
   string str_editText = m_editLots.Text();
   double d_lots = StringToDouble( str_editText );
   d_lots += 0.01;
   m_editLots.Text( DoubleToStr( d_lots, 2 ) );
}
void CPanelDialog::OnClickBtnDown()
{
   m_btnDown.Pressed( false );
   
   string str_editText = m_editLots.Text();
   double d_lots = StringToDouble( str_editText );
   if( d_lots > 0.01 )
   {
      d_lots -= 0.01;
      m_editLots.Text( DoubleToStr( d_lots, 2 ) );
   }
}

AppWindo.mqh の ソースコード詳細

1. [ AppWindow.mqh ] include文

今回は、プルダウンを使うので、ComboBoxをインクルードします。

AppWindow.mqh
#include <Controls\ComboBox.mqh>

2. [ AppWindow.mqh ] CreateCombCreate()関数

Createって2回言っとるよ...
AddItemでプルダウンメニューの中身を追加します。
m_combCreate.AddItem( "All Exit", 0 );
m_combCreate.AddItem( "This Exit", 1 );
メンバ変数 . AddItem( 表示文字列, 番号 );

AppWindow.mqh
bool CPanelDialog::CreateCombCreate()
{
   int widths = ClientAreaWidth() / 5;
   int x1 = 0;
   int y1 = ClientAreaHeight() - 20;
   int x2 = widths * 4;
   int y2 = ClientAreaHeight();
   
   if( !m_combCreate.Create( m_chart_id, m_name + "comboCreate", m_subwin, x1, y1, x2, y2 ) ) return false;
   m_combCreate.AddItem( "All Exit", 0 );
   m_combCreate.AddItem( "This Exit", 1 );
   
   if( !Add( m_combCreate ) ) return false;
   
   return true;
}

ExitCurrency.mqh ( New )

ExitCurrency.mqh
class CExitCurrency
{
   public:
      bool exit();
      bool exit( string str_symbol );
};
bool CExitCurrency::exit()     // --- 3
{
   if( OrdersTotal() == 0 )
      Alert( "not Order" );
   else
   {
      for( int i = OrdersTotal() - 1; i >= 0; i-- )
      {
         if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
         if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
         Sleep( 10 );
      }
   }   
   
   return true;
}
bool CExitCurrency::exit( string str_symbol )     // --- 4
{
   for( int i = OrdersTotal() - 1; i >= 0; i-- )
   {
      if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
      if( OrderSymbol() != str_symbol ) continue;
      if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
      Sleep( 10 );
   }
   
   return true;
}

ExitCurrency.mqh の ソースコード詳細

3. [ ExitCurrency.mqh ] exit関数 ( 全決済 )

ポジションがあれば、全決済をします。

ExitCurrency.mqh
bool CExitCurrency::exit()     // --- 3
{
   if( OrdersTotal() == 0 )
      Alert( "not Order" );
   else
   {
      for( int i = OrdersTotal() - 1; i >= 0; i-- )
      {
         if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
         if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
         Sleep( 10 );
      }
   }   
   
   return true;
}

if( OrdersTotal() == 0 )
OrdersTotal()を使い、ポジションがあるかどうかを判別してます。
for( int i = OrdersTotal() - 1; i >= 0; i-- )
MT4では、いったんポジションが決済されると、
各ポジションに付されたインデックスが再び古いものから順に『0』から振り直されるので、
( ポジション合計数 - 1 ) になります。
なので、新しい → → → 古い と検索します。
if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
OrderSelect関数を使って、エントリー中の注文を選択します。
OrderSelectで選択できなかったら、continue; で戻ります。
if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
上記を全てクリアしたら、いよいよ決済です。
OrderClose関数を使用して、決済します。
OrderSelectでポジションを選択済みなので、( チケット、ロット、価格、スリップページ ) を使って決済します。
Sleep( 100 );
OrderCloseは、負荷が掛かるので、0.1秒 休止させます。
※Sleepしないと、次のポジション決済に影響がでる可能性があります。

4. [ ExitCurrency.mqh ] exit関数 ( 個別決済 )

通貨ペアの比較で、個別決済を実装します。
他は、全決済と同じです。

ExitCurrency.mqh
bool CExitCurrency::exit( string str_symbol )
{
   for( int i = OrdersTotal() - 1; i >= 0; i-- )
   {
      if( !OrderSelect( i, SELECT_BY_POS, MODE_TRADES ) ) continue;
      if( OrderSymbol() != str_symbol ) continue;
      if( !OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), 0 ) ) return false;
      Sleep( 10 );
   }
   
   return true;
}

bool CExitCurrency::exit( string str_symbol )
引数で、Pushをした通貨ペアを取得します
if( OrderSymbol() != str_symbol ) continue;
全ポジションを比較し、通貨ペアが同じなら、決済します。


Event.mqh

Event.mqh
#include "AppWindow.mqh"
#include "Plugin/ExitCurrency.mqh"
CPanelDialog   AppWindow;
CExitCurrency  ExitCurrency;
class CEvent
{
   public:
      bool  OnEvent( const int id, const long lparam, const double dparam, const string sparam );
      
   private:
      bool  btnOrder( const int id, const long lparam, const double dparam, const string sparam );
      bool  Order( int i_type, double d_lots );
      bool  combSelect( const int id, const long lparam, const double dparam, const string sparam );
};
bool CEvent::OnEvent( const int id, const long lparam, const double dparam, const string sparam )
{
   if( !btnOrder( id, lparam, dparam, sparam ) )
      Alert( "Error : " + (string)GetLastError() );
   if( !combSelect( id, lparam, dparam, sparam ) )
      Alert( "Error : " + (string)GetLastError() );   
   
   return true;
}
bool CEvent::btnOrder( const int id, const long lparam, const double dparam, const string sparam )
{
   if( ( StringFind( sparam, "btnBuy", 4 ) != -1 ) && id == CHARTEVENT_OBJECT_CLICK ) 
   {
      if( !Order( 0, (double)AppWindow.m_editLots.Text() ) )
         Alert( "Error : " + (string)GetLastError() );
   }else if( ( StringFind( sparam, "btnSell", 4 ) != -1 ) && id == CHARTEVENT_OBJECT_CLICK ) 
   {
      if( !Order( 1, (double)AppWindow.m_editLots.Text() ) )
         Alert( "Error : " + (string)GetLastError() );
   }
   
   return true;
}
bool CEvent::Order( int i_type, double d_lots )
{
   if( OrderSend( Symbol(), i_type, d_lots, Close[0], 0, 0, 0, "GUISample", 999, 0, clrRed ) == -1 )
      return false;
   else
      Alert( "OrderSend Success!!\n Lots = " + (string)d_lots + "\n type = " + (string)i_type );
   
   return true;
}
bool CEvent::combSelect( const int id, const long lparam, const double dparam, const string sparam )
{
   if( ( StringFind( sparam, "btnComb", 4 ) != -1 ) && id == CHARTEVENT_OBJECT_CLICK ) 
   {
      switch( (int)AppWindow.m_combCreate.Value() )       // --- 5
      {
         case 0: // to All Exit
            if( !ExitCurrency.exit() )
               Alert( "Error : " + (string)GetLastError() );
            break;
         case 1: // to This Exit
            if( !ExitCurrency.exit( Symbol() ) )
               Alert( "Error : " + (string)GetLastError() );
            break;
         default:
            Alert( "not select" );
      }
   }
   
   return true;
}

Event.mqh の ソースコード詳細

5. [ Exit.mqh ] combSelect関数

Pushのボタンを押した際に、ComboBoxの番号を取得します。
switch文で、番号ごとの命令を追加。

Event.mqh
bool CEvent::combSelect( const int id, const long lparam, const double dparam, const string sparam )
{
   if( ( StringFind( sparam, "btnComb", 4 ) != -1 ) && id == CHARTEVENT_OBJECT_CLICK ) 
   {
      switch( (int)AppWindow.m_combCreate.Value() )
      {
         case 0: // to All Exit
            if( !ExitCurrency.exit() )
               Alert( "Error : " + (string)GetLastError() );
            break;
         case 1: // to This Exit
            if( !ExitCurrency.exit( Symbol() ) )
               Alert( "Error : " + (string)GetLastError() );
            break;
         default:
            Alert( "not select" );
      }
   }
   
   return true;
}

switch( (int)AppWindow.m_combCreate.Value() )
Editのロットを取得したのと同じ様に、ComboBoxの値を取得します。
AppWindow. メンバ変数 . Value()
if( !ExitCurrency.exit( Symbol() ) )
( case 1 )個別決済だったら、exitの引数に、通貨ペアを渡します。

さいごに

今回は、全決済、個別決済を実装しました。
コードが長そうに見えますが、凄く単純です。
次回は、水平ラインタッチで、決済(ストップ狩りの対処かも?) を実装します。
コードをGithubに up した方がいいのかな。。。
YoutubeでLive配信しながら作ってます。
https://www.youtube.com/channel/UCcTw_iVgpLfrep9f94KxwLg?sub_confirmation=1
チャンネル登録お願いします:relaxed:
Twitterでは毎日呟いています。
https://twitter.com/IceSeed_bz
フォローお願いします:relaxed:
お疲れ様。:eye::eye:

1
4
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?