C
MQL4
MT4
Dialog
4
どのような問題がありますか?

投稿日

更新日

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

はじめに

ここでは、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:

新規登録して、もっと便利にQiitaを使ってみよう

  1. ユーザーやタグをフォローできます
  2. 便利な情報をストックできます
  3. 記事の編集提案をすることができます
ログインすると使える機能について
IceSeed
何か始めようとして取りあえず作った。 youtube :【https://www.youtube.com/channel/UCcTw_iVgpLfrep9f94KxwLg?sub_confirmation=1】

コメント

この記事にコメントはありません。
あなたもコメントしてみませんか :)
新規登録
すでにアカウントを持っている方はログイン
4
どのような問題がありますか?
新規登録して、Qiitaをもっと便利に使ってみませんか

この機能を利用するにはログインする必要があります。ログインするとさらに下記の機能が使えます。

  1. ユーザーやタグのフォロー機能であなたにマッチした記事をお届け
  2. ストック機能で便利な情報を後から効率的に読み返せる
新規登録ログイン
ストックするカテゴリー