クイック手動取引ツールキット: 基本機能

Alexander Fedosov | 12 10月, 2020

内容

はじめに

今日、多くのトレーダーが自動取引システムに切り替えています。これらのシステムには、追加のセットアップが必要なものも完全に自動化されてすぐに使用できるものもあります。ただし、昔ながらの方法で手動で取引することを好むトレーダーもかなりいます。彼らは、特定の取引状況ごとに意思決定をおこなう際に、人間の専門家の判断を得るのを好みます。そのような状況は時折急速に発展するので、トレーダーは迅速に対応する必要があります。また、一部の取引スタイル(スキャルピングなど)では、注文を出すタイミングを正確にする必要があります。このようなときに、追加のツールが役立つ場合があります。これらのツールは、発注や決済やなどの目的のアクションを可能な限り最速で実装できます。そのため、迅速な手動取引のニーズに対応するための基本機能を実装することにしました。

ツールキットの概念

まず、手動取引で必要になる可能性のある一連の基本的なアクションを決定して、これに基づいて、適切なアクションを効率的かつ迅速に実行できるツールを開発します。手動取引には基礎となる取引システムがあります。これは、成行注文または指値注文のいずれかです。したがって、ツールキットの主な基準は、これら2つの注文タイプを処理できることです。また、取引の過程でトレーダーが実行できるタスクを選択することもできます。ツールは、これらのタスクの実行に必要な時間とアクションの数を減らすのに役立ちます。

図1 メインツールキットウィンドウ

図1は、成行注文と指値注文の2つのカテゴリを示しています。また、迅速な実行が必要な場合もありますが、1つのアクションでは実行できない3つの基本的なタスクを選択しました。MetaTrader 5ターミナルを含む多くのアプリケーションには、特定のコマンドまたはアクションの迅速な実行を可能にするホットキーの基本セットがあります。ここでのアプリケーションはこの事実を考慮に入れます。ホットキーは括弧内に示されます。ホットキーが押されると、指定されたアクションが実行され、注文を処理するときには適切なウィンドウが開きます。マウスを使用してアクションを実行することも可能になります。たとえば、収益性の高いすべての注文を決済するには、Cキーを押すか、[Close all profitable](すべての収益性の高い注文を決済)をクリックします。 

Mを押すか、[Market order](成行注文)をクリックすると、[Settings: Market order](設定: 成行注文)ウィンドウが開きます。このウィンドウには、成行買い注文または成行売り注文を出すためのデータを入力するためのオプションが含まれています。 

図2 成行注文を構成および作成するためのウィンドウ

基本的な設定に加えて、ターミナル同様に、ロットは数値としてだけでなく、口座残高のパーセントとしても選択できます。これは、価格形式だけでなく、ポイントでも同様に、テイクプロフィットとストップロスにも関係します。買いと売りは、適切なボタンをクリックする方法と、角かっこで指定されたホットキーを押す方法の2つで実行できます。 

Pを押すと、指値注文設定ウィンドウを開きます。4つの指値注文タイプがサポートされています。 

図3 指値注文を構成および作成するためのウィンドウ

成行注文と同様に、指値注文は、数値または残高のパーセントとしてのロット、および、価格またはポイントでのテイクプロフィットとストップロスの選択に対応しています。 


ツールの実装

まず、初期のプロジェクト構造を作成しましょう。以下の図4に示すように、Expertsディレクトリを開き、いくつかのファイルを含む「SimpleTrading」フォルダを作成します。

図4 プロジェクトファイルの構造

作成したファイルの目的を考えてみましょう。

まず、Program.mqhを開き、インターフェイスと取引関数の実装に必要なライブラリを接続して、CFastTradingクラスを作成します。

//+------------------------------------------------------------------+
//|                                                      Program.mqh |
//|                                                         Alex2356 |
//|                    https://www.mql5.com/en/users/alex2356/seller |
//+------------------------------------------------------------------+
#include <EasyAndFastGUI\WndEvents.mqh>
#include <DoEasy25\Engine.mqh>
#include "Defines.mqh"
//+------------------------------------------------------------------+
//| Enumeration for switching the interface language                 |
//+------------------------------------------------------------------+
enum LANG
{
   RUSSIAN,       // Russian
   ENGLISH        // English
};
//+------------------------------------------------------------------+
//| Class for creating an application                                |
//+------------------------------------------------------------------+
class CFastTrading : public CWndEvents
{
public:
                     CFastTrading(void);
                    ~CFastTrading(void);
   //--- Initialization/deinitialization
   void              OnInitEvent(void);
   void              OnDeinitEvent(const int reason);
   //--- Timer
   void              OnTimerEvent(void);
   //--- Chart event handler
   virtual void      OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam);
};
//+------------------------------------------------------------------+
//| Adding GUI elements                                              |
//+------------------------------------------------------------------+
#include "MainWindow.mqh"
//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CFastTrading::CFastTrading(void)
{
}
//+------------------------------------------------------------------+
//| Destructor                                                       |
//+------------------------------------------------------------------+
CFastTrading::~CFastTrading(void)
{
}
//+------------------------------------------------------------------+
//| Initialization                                                    |
//+------------------------------------------------------------------+
void CFastTrading::OnInitEvent(void)
{
}
//+------------------------------------------------------------------+
//| Deinitialization                                                 |
//+------------------------------------------------------------------+
void CFastTrading::OnDeinitEvent(const int reason)
{
//--- Remove the interface
   CWndEvents::Destroy();
}
//+------------------------------------------------------------------+
//| Timer                                                            |
//+------------------------------------------------------------------+
void CFastTrading::OnTimerEvent(void)
{
   CWndEvents::OnTimerEvent();
//---
}
//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
}
//+------------------------------------------------------------------+


次に、SimpleTrading.mq5EAファイルを開き、Program.mqhを接続して、新しく作成されたクラスの場合はインスタンスを作成しますまた、入力パラメータを設定します。これには次のものが含まれます。

//+------------------------------------------------------------------+
//|                                                SimpleTrading.mq5 |
//|                                                         Alex2356 |
//|                    https://www.mql5.com/en/users/alex2356/seller |
//+------------------------------------------------------------------+
#property copyright "Copyright 2020, Alexander Fedosov"
#property link      "https://www.mql5.com/en/users/alex2356"
#property version   "1.00"
//--- Include application class
#include "Program.mqh"
//+------------------------------------------------------------------+
//| Expert Advisor input parameters                                  |
//+------------------------------------------------------------------+
input int                  Inp_BaseFont      =  10;                  // Base FontSize 
input color                Caption           =  C'0,130,225';        // Caption Color
input color                Background        =  clrWhite;            // Back color
input LANG                 Language          =  ENGLISH;             // Interface language
input ulong                MagicNumber       =  1111;                // Magic Number
//---
CFastTrading program;
ulong tick_counter;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   tick_counter=GetTickCount();
//---
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   program.OnDeinitEvent(reason);
}
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{
//---
}
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer(void)
{
   program.OnTimerEvent();
}
//+------------------------------------------------------------------+
//| ChartEvent function                                              |
//+------------------------------------------------------------------+
void OnChartEvent(const int    id,
                  const long   &lparam,
                  const double &dparam,
                  const string &sparam)
{
   program.ChartEvent(id,lparam,dparam,sparam);
//---
   if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI)
   {
      Print("End in ",GetTickCount()-tick_counter," ms");
   }
}
//+------------------------------------------------------------------+


このクラスでEA入力パラメータを使用できるようにするには、EA設定値が割り当てられる変数と、実装に使用されるメソッドを作成する必要があります。クラスのprivateセクションに変数を作成します。

private:
//---
   color             m_caption_color;
   color             m_background_color;
//---
   int               m_base_font_size;
   int               m_m_edit_index;
   int               m_p_edit_index;
//---
   ulong             m_magic_number;
//---
   string            m_base_font;
//---
   LANG              m_language;

クラスのpublicセクションでメソッドを作成します。

   //--- Caption color
   void              CaptionColor(const color clr);
   //--- Background color
   void              BackgroundColor(const color clr);
   //--- Font size
   void              FontSize(const int font_size);
   //--- Font name
   void              FontName(const string font_name);
   //--- Setting the interface language
   void              SetLanguage(const LANG lang);
   //--- Setting the magic number
   void              SetMagicNumber(ulong magic_number);

実装は次のとおりです。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::CaptionColor(const color clr)
{
   m_caption_color=clr;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::BackgroundColor(const color clr)
{
   m_background_color=clr;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::FontSize(const int font_size)
{
   m_base_font_size=font_size;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::FontName(const string font_name)
{
   m_base_font=font_name;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::SetLanguage(const LANG lang)
{
   m_language=lang;
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::SetMagicNumber(const ulong magic_number)
{
   m_magic_number=magic_number;
}

次に、EAの初期化にそれらを適用します。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   tick_counter=GetTickCount();
//--- Initialize class variables
   program.FontSize(Inp_BaseFont);
   program.BackgroundColor(Background);
   program.CaptionColor(Caption);
   program.SetLanguage(Language);
   program.SetMagicNumber(MagicNumber);
//---
   return(INIT_SUCCEEDED);
}

インターフェイス全体を作成するCreateGUI()メソッドを追加します。このメソッドは今のところ空ですが、UI要素を作成するときに内容が追加されます。

//--- Create the graphical interface of the program
   bool              CreateGUI(void);

このメソッドはEAの初期化に追加できます。

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
//---
   tick_counter=GetTickCount();
//--- Initialize class variables
   program.FontName("Trebuchet MS");
   program.FontSize(Inp_BaseFont);
   program.BackgroundColor(Background);
   program.CaptionColor(Caption);
   program.SetLanguage(Language);
   program.SetMagicNumber(MagicNumber);
//--- Set up the trading panel
   if(!program.CreateGUI())
   {
      Print(__FUNCTION__," > Failed to create graphical interface!");
      return(INIT_FAILED);
   }
//---
   return(INIT_SUCCEEDED);
}

次に、メインアプリケーションウィンドウを作成します。これは、CreateMainWindow()メソッドをクラスのprotectedセクションに追加することで実行できます。 

protected:
   //--- forms
   bool              CreateMainWindow(void);

実装をMainWindow.mqhファイルに追加してから、CreateGUI()で呼び出しますこのメソッドの実装では、CAPTION_NAMEマクロ置換を使用したため、特別なDefines.mqh ファイルに作成します。

//+------------------------------------------------------------------+
//| Creates a form for orders                                        |
//+------------------------------------------------------------------+
bool CFastTrading::CreateMainWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_main_window);
//--- Properties
   m_main_window.XSize(400);
   m_main_window.YSize(182);
//--- Coordinates
   int x=5;
   int y=20;
   m_main_window.CaptionHeight(22);
   m_main_window.IsMovable(true);
   m_main_window.CaptionColor(m_caption_color);
   m_main_window.CaptionColorLocked(m_caption_color);
   m_main_window.CaptionColorHover(m_caption_color);
   m_main_window.BackColor(m_background_color);
   m_main_window.FontSize(m_base_font_size);
   m_main_window.Font(m_base_font);
//--- Create the form
   if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y))
      return(false);
//---
   return(true);
}
//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CFastTrading::CreateGUI(void)
{
//--- Create the main application window
   if(!CreateMainWindow())
      return(false);
//--- Complete GUI creation
   CWndEvents::CompletedGUI();
   return(true);
}

次に、新しいマクロ置換を作成します。

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#include "Program.mqh"
#define CAPTION_NAME                   (m_language==RUSSIAN ? "Быстрый трейдинг" : "Fast Trading")

プロジェクトをコンパイルして、メインアプリケーションウィンドウを取得します。次に、説明したアクションを実行するボタン(図1)を追加します。それらを実装するには、クラスのprotectedセクションに汎用CreateButton()メソッドを作成します。

//--- Buttons
   bool              CreateButton(CWindow &window,CButton &button,string text,color baseclr,int x_gap,int y_gap,int w_number);
  

MainWindow.mqhに実装し、メインウィンドウ作成メソッド本体に適用します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateButton(CWindow &window,CButton &button,string text,color baseclr,int x_gap,int y_gap,int w_number)
{
//--- Store the window pointer
   button.MainPointer(window);
//--- Set properties before creation
   button.XSize(170);
   button.YSize(40);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(baseclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(baseclr);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create a control element
   if(!button.CreateButton(text,x_gap,window.CaptionHeight()+y_gap))
      return(false);
//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(w_number,button);
   return(true);
}
//+------------------------------------------------------------------+
//| Creates a form for orders                                        |
//+------------------------------------------------------------------+
bool CFastTrading::CreateMainWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_main_window);
//--- Properties
   m_main_window.XSize(400);
   m_main_window.YSize(182);
//--- Coordinates
   int x=5;
   int y=20;
   m_main_window.CaptionHeight(22);
   m_main_window.IsMovable(true);
   m_main_window.CaptionColor(m_caption_color);
   m_main_window.CaptionColorLocked(m_caption_color);
   m_main_window.CaptionColorHover(m_caption_color);
   m_main_window.BackColor(m_background_color);
   m_main_window.FontSize(m_base_font_size);
   m_main_window.Font(m_base_font);
   m_main_window.TooltipsButtonIsUsed(true);
//--- Create the form
   if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y))
      return(false);
//---
   if(!CreateButton(m_main_window,m_order_button[0],MARKET_ORDER_NAME+"(M)",C'87,128,255',20,10,0))
      return(false);
   if(!CreateButton(m_main_window,m_order_button[1],PENDING_ORDER_NAME+"(P)",C'31,209,111',210,10,0))
      return(false);
   if(!CreateButton(m_main_window,m_order_button[2],MARKET_ORDERS_PROFIT_CLOSE+"(C)",C'87,128,255',20,60,0))
      return(false);
   if(!CreateButton(m_main_window,m_order_button[3],MARKET_ORDERS_LOSS_CLOSE+"(D)",C'87,128,255',20,110,0))
      return(false);
   if(!CreateButton(m_main_window,m_order_button[4],PEND_ORDERS_ALL_CLOSE+"(R)",C'31,209,111',210,60,0))
      return(false);
   return(true);
}

ここではマクロ置換も使用されるため、Defines.mqhに追加します。

//+------------------------------------------------------------------+
//| Macro substitutions                                              |
//+------------------------------------------------------------------+
#include "Program.mqh"
#define CAPTION_NAME                   (m_language==RUSSIAN ? "Быстрый трейдинг" : "Fast Trading System")
#define MARKET_ORDER_NAME              (m_language==RUSSIAN ? "Рыночный ордер" : "Marker Order")
#define PENDING_ORDER_NAME             (m_language==RUSSIAN ? "Отложенный ордер" : "Pending Order")
#define MARKET_ORDERS_PROFIT_CLOSE     (m_language==RUSSIAN ? "Закрыть все прибыльные" : "Close all profitable")
#define MARKET_ORDERS_LOSS_CLOSE       (m_language==RUSSIAN ? "Закрыть все убыточные" : "Close all losing")
#define PEND_ORDERS_ALL_CLOSE          (m_language==RUSSIAN ? "Закрыть все отложенные" : "Close all pending")

これは、英語版が選択されたときに表示されるものです。

図5 メインアプリケーションウィンドウ

前述のように、アプリケーションには、成行注文と指値注文を処理するためのウィンドウがさらに2つ必要なので、作成して、成行注文ボタンと保留中注文ボタンにリンクします。関連する操作は、ボタンをクリックするか、MおよびPホットキーを押すことで実行できます。したがって、クラスのprotectedセクションにCreateMarketOrdersWindow()CreatePendingOrdersWindow()の2つのメソッドを追加し、MainWindow.mqhで実装します

   bool              CreateMarketOrdersWindow(void);
   bool              CreatePendingOrdersWindow(void);
//+------------------------------------------------------------------+
//| Market order creation and editing window                         |
//+------------------------------------------------------------------+
bool CFastTrading::CreateMarketOrdersWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_orders_windows[0]);
//--- Properties
   m_orders_windows[0].XSize(450);
   m_orders_windows[0].YSize(242+58);
//--- Coordinates
   int x=m_order_button[0].XGap();
   int y=m_order_button[0].YGap()+60;
//---
   color clrmain=C'87,128,255';
//---
   m_orders_windows[0].CaptionHeight(22);
   m_orders_windows[0].IsMovable(true);
   m_orders_windows[0].CaptionColor(clrmain);
   m_orders_windows[0].CaptionColorLocked(clrmain);
   m_orders_windows[0].CaptionColorHover(clrmain);
   m_orders_windows[0].BackColor(m_background_color);
   m_orders_windows[0].BorderColor(clrmain);
   m_orders_windows[0].FontSize(m_base_font_size);
   m_orders_windows[0].Font(m_base_font);
   m_orders_windows[0].WindowType(W_DIALOG);
//--- Create the form
   if(!m_orders_windows[0].CreateWindow(m_chart_id,m_subwin,CAPTION_M_ORD_NAME,x,y))
      return(false);
   return(true);
}
//+------------------------------------------------------------------+
//| Pending order creation and editing window                        |
//+------------------------------------------------------------------+
bool CFastTrading::CreatePendingOrdersWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_orders_windows[1]);
//--- Properties
   m_orders_windows[1].XSize(600);
   m_orders_windows[1].YSize(580);
//--- Coordinates
   int x=m_order_button[0].XGap();
   int y=m_order_button[0].YGap()+60;
//---
   color clrmain=C'31,209,111';
//---
   m_orders_windows[1].CaptionHeight(22);
   m_orders_windows[1].IsMovable(true);
   m_orders_windows[1].CaptionColor(clrmain);
   m_orders_windows[1].CaptionColorLocked(clrmain);
   m_orders_windows[1].CaptionColorHover(clrmain);
   m_orders_windows[1].BackColor(m_background_color);
   m_orders_windows[1].BorderColor(clrmain);
   m_orders_windows[1].FontSize(m_base_font_size);
   m_orders_windows[1].Font(m_base_font);
   m_orders_windows[1].WindowType(W_DIALOG);
//--- Create the form
   if(!m_orders_windows[1].CreateWindow(m_chart_id,m_subwin,CAPTION_P_ORD_NAME,x,y))
      return(false);
   return(true);
}

これらの2つのウィンドウではマクロ置換が使用されるため、適切なファイルに追加します。

#define CAPTION_M_ORD_NAME             (m_language==RUSSIAN ? "Настройка: Рыночный Ордер" : "Setting: Market Order")
#define CAPTION_P_ORD_NAME             (m_language==RUSSIAN ? "Настройка: Отложенный Ордер" : "Setting: Pending Order")

ここで、アプリケーションインターフェイスが作成されているCreateGUI()基本メソッドで新しく作成されたウィンドウを呼び出します。

//+------------------------------------------------------------------+
//| Creates the graphical interface of the program                   |
//+------------------------------------------------------------------+
bool CFastTrading::CreateGUI(void)
{
//--- Create the main application window
   if(!CreateMainWindow())
      return(false);
   if(!CreateMarketOrdersWindow())
      return(false);
   if(!CreatePendingOrdersWindow())
      return(false);
//--- Complete GUI creation
   CWndEvents::CompletedGUI();
   return(true);
}

これらの作成されたウィンドウはダイアログであるため、アプリケーションの起動時には表示されません。それらを表示するメカニズムを作成する必要があります。成行注文/指値注文ボタンをクリックするか、ホットキーを押すと開くようにします。基本クラスでOnEvent()メソッド本体を見つけ、必要な条件を記述します。

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//--- Pressing the button event
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
   {
      //---
      if(lparam==m_order_button[0].Id())
         m_orders_windows[0].OpenWindow();
      //---
      if(lparam==m_order_button[1].Id())
         m_orders_windows[1].OpenWindow();
   }
//--- Key press event
   if(id==CHARTEVENT_KEYDOWN)
   {
      //--- Opening a market order window
      if(lparam==KEY_M)
      {
         if(m_orders_windows[0].IsVisible())
         {
            m_orders_windows[0].CloseDialogBox();
         }
         else
         {
            if(m_orders_windows[1].IsVisible())
            {
               m_orders_windows[1].CloseDialogBox();
            }
            //---
            m_orders_windows[0].OpenWindow();
         }
      }
      //--- Opening a pending order window
      if(lparam==KEY_P)
      {
         if(m_orders_windows[1].IsVisible())
         {
            m_orders_windows[1].CloseDialogBox();
         }
         else
         {
            if(m_orders_windows[0].IsVisible())
            {
               m_orders_windows[0].CloseDialogBox();
            }
            //---
            m_orders_windows[1].OpenWindow();
         }
      }
   }
}

次に、プロジェクトをコンパイルし、ホットキーを使用してダイアログボックスを開いてみます。結果は、図6に示すようになります。

図6 ホットキーを使用してウィンドウを開いたり切り替えたりする

ご覧のとおり、別のダイアログウィンドウを開く前にダイアログウィンドウを閉じる必要はありません。別のウィンドウに切り替えるだけです。ワンクリックで成行注文と指値注文を切り替え、時間を節約できます。もう1つのささやかながら便利な機能は、Escキーを使用してダイアログを閉じる機能です。ウィンドウの開き具合をテストするとき、私はこのキーを数回使用してウィンドウを閉じていました。イベントセクションにコードを追加することにします。

      //--- Exiting the order placing window
      if(lparam==KEY_ESC)
      {
         if(m_orders_windows[0].IsVisible())
         {
            m_orders_windows[0].CloseDialogBox();
         }
         else if(m_orders_windows[1].IsVisible())
         {
            m_orders_windows[1].CloseDialogBox();
         }
      }

それでは、[Market Orders](成行注文)ウィンドウから始めて、作成したウィンドウで作業を続けます。図2によると、2つ(売買)の注文管理ブロックを作成する必要があります。まず、新しいCreateFrame()メソッドを使用して、2つのインターフェイス要素(フレーム)を作成します。

bool              CreateFrame(CWindow &window,CFrame &frame,const int x_gap,const int y_gap,string caption,int w_number);

その実装は次のとおりです。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateFrame(CWindow &window,CFrame &frame,const int x_gap,const int y_gap,string caption,int w_number)
{
//--- Store the pointer to the main control
   frame.MainPointer(window);
//---
   color clrmain=clrNONE;
   if(caption==BUY_ORDER)
      clrmain=C'88,212,210';
   else if(caption==SELL_ORDER)
      clrmain=C'236,85,79';
//---
   frame.YSize(110);
   frame.LabelColor(clrmain);
   frame.BorderColor(clrmain);
   frame.BackColor(m_background_color);
   frame.GetTextLabelPointer().BackColor(m_background_color);
   frame.Font(m_base_font);
   frame.FontSize(m_base_font_size);
   frame.AutoXResizeMode(true);
   frame.AutoXResizeRightOffset(10);
//--- Create a control element
   if(!frame.CreateFrame(caption,x_gap,window.CaptionHeight()+y_gap))
      return(false);
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(w_number,frame);
   return(true);
}

フレーム作成の実装にはフレームヘッダの2つの新しいマクロ置換があるため、Defines.mqhに追加します

#define BUY_ORDER                      (m_language==RUSSIAN ? "Buy-ордер" : "Buy-order")
#define SELL_ORDER                     (m_language==RUSSIAN ? "Sell-ордер" : "Sell-order")

このメソッドを適用するには、成行注文を作成するCreateMarketOrdersWindow()メソッドの本文の最後に移動し、次を追加します

...
//--- Create the form
   if(!m_orders_windows[0].CreateWindow(m_chart_id,m_subwin,CAPTION_M_ORD_NAME,x,y))
      return(false);
//--- BUY BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[0],10,20,BUY_ORDER,1))
      return(false);
//--- SELL BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[1],10,160,SELL_ORDER,1))
      return(false);
   return(true);
}

結果を確認します。

図7 成行注文のブロック

図7の各ブロックには、UI要素の4つの主要なカテゴリが含まれます。

各カテゴリの段階的な実装を進めます。テキストヘッダ用のCreateLabel()汎用メソッドを作成します。

//+------------------------------------------------------------------+
//| Creates the text label                                           |
//+------------------------------------------------------------------+
bool CFastTrading::CreateLabel(CWindow &window,CTextLabel &text_label,const int x_gap,const int y_gap,string label_text,int w_number)
{
//--- Store the window pointer
   text_label.MainPointer(window);
//---
   text_label.Font(m_base_font);
   text_label.FontSize(m_base_font_size);
   text_label.XSize(80);
   text_label.BackColor(m_background_color);
   text_label.IsCenterText(true);
//--- Creating a label
   if(!text_label.CreateTextLabel(label_text,x_gap,window.CaptionHeight()+y_gap))
      return(false);
//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(w_number,text_label);
   return(true);
}

以前に成行注文作成メソッドを補足しましたが、ここで、現在の実装を考慮して、以下を追加します。

//--- BUY BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[0],10,20,BUY_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[0],20,30,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[1],20+80+20,30,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[2],20+(80+20)*2,30,SL,1))
      return(false);
//--- SELL BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[1],10,160,SELL_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[3],20,170,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[4],20+80+20,170,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[5],20+(80+20)*2,170,SL,1))
      return(false);
   return(true);
}

Lot、Take Profit、StopLossの3つの新しいマクロ置換があります。2言語で名前を追加します。

#define LOT                            (m_language==RUSSIAN ? "Лот" : "Lot")
#define TP                             (m_language==RUSSIAN ? "Тейк профит" : "Take Profit")
#define SL                             (m_language==RUSSIAN ? "Стоп лосс" : "Stop Loss")

 次のカテゴリには切り替えボタンが含まれます。特別に作成されたメソッドCreateSwitchButton()が使用されます。 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateSwitchButton(CWindow &window,CButton &button,string text,int x_gap,int y_gap,int w_number)
{
//--- Store the window pointer
   button.MainPointer(window);
   color baseclr=clrSlateBlue;
   color pressclr=clrIndigo;
//--- Set properties before creation
   button.XSize(80);
   button.YSize(24);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(pressclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(pressclr);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
   button.TwoState(true);
//--- Create a control element
   if(!button.CreateButton(text,x_gap,window.CaptionHeight()+y_gap))
      return(false);
//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(w_number,button);
   return(true);
}

CreateMarketWindow()メソッドの両方のブロックに適用します。

...
//--- BUY BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[0],10,20,BUY_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[0],20,30,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[1],20+80+20,30,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[2],20+(80+20)*2,30,SL,1))
      return(false);
//--- Toggle buttons
   for(int i=0; i<3; i++)
      if(!CreateSwitchButton(m_orders_windows[0],m_switch_button[i],"-",20+(80+20)*i,60,1))
         return(false);
//--- SELL BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[1],10,160,SELL_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[3],20,170,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[4],20+80+20,170,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[5],20+(80+20)*2,170,SL,1))
      return(false);
//--- Toggle buttons
   for(int i=3; i<6; i++)
      if(!CreateSwitchButton(m_orders_windows[0],m_switch_button[i],"-",20+(80+20)*(i-3),170+30,1))
         return(false);
   return(true);
}

要素には特定の使用制限が必要なため、入力フィールドに関連する次のカテゴリには特別な注意を払う必要があります。たとえば、[Lot](ロット)入力フィールドの値は、現在の銘柄仕様と取引口座の詳細によって制限される必要があります。このフィールドを編集するときは、最小および最大ロットサイズおよび最小変更ステップパラメータを考慮する必要があります。これに基づいて、CreateLotEdit()を作成し、それに応じて入力フィールドを設定します

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateLotEdit(CWindow &window,CTextEdit &text_edit,const int x_gap,const int y_gap,int w_number)
{
//--- Store the pointer to the main control
   text_edit.MainPointer(window);
//--- Properties
   text_edit.XSize(80);
   text_edit.YSize(24);
   text_edit.Font(m_base_font);
   text_edit.FontSize(m_base_font_size);
   text_edit.MaxValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX));
   text_edit.StepValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP));
   text_edit.MinValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN));
   text_edit.SpinEditMode(true);
   text_edit.SetDigits(2);
   text_edit.GetTextBoxPointer().XGap(1);
   text_edit.GetTextBoxPointer().XSize(80);
//--- Create a control element
   if(!text_edit.CreateTextEdit("",x_gap,window.CaptionHeight()+y_gap))
      return(false);
   text_edit.SetValue(string(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN)));
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(w_number,text_edit);
   return(true);
}

また、ストップロスとテイクプロフィットの入力フィールドを作成します。上記のすべてを成行注文作成ウィンドウに追加します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateTakeProfitEdit(CWindow &window,CTextEdit &text_edit,const int x_gap,const int y_gap,int w_number)
{
//--- Store the pointer to the main control
   text_edit.MainPointer(window);
//--- Properties
   text_edit.XSize(80);
   text_edit.YSize(24);
   text_edit.Font(m_base_font);
   text_edit.FontSize(m_base_font_size);
   text_edit.MaxValue(9999);
   text_edit.StepValue(1);
   text_edit.MinValue(0);
   text_edit.SpinEditMode(true);
   text_edit.GetTextBoxPointer().XGap(1);
   text_edit.GetTextBoxPointer().XSize(80);
//--- Create a control element
   if(!text_edit.CreateTextEdit("",x_gap,window.CaptionHeight()+y_gap))
      return(false);
   text_edit.SetValue(string(150));
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(w_number,text_edit);
   return(true);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateStopLossEdit(CWindow &window,CTextEdit &text_edit,const int x_gap,const int y_gap,int w_number)
{
//--- Store the pointer to the main control
   text_edit.MainPointer(window);
//--- Properties
   text_edit.XSize(80);
   text_edit.YSize(24);
   text_edit.Font(m_base_font);
   text_edit.FontSize(m_base_font_size);
   text_edit.MaxValue(9999);
   text_edit.StepValue(1);
   text_edit.MinValue(0);
   text_edit.SpinEditMode(true);
   text_edit.GetTextBoxPointer().XGap(1);
   text_edit.GetTextBoxPointer().XSize(80);
//--- Create a control element
   if(!text_edit.CreateTextEdit("",x_gap,window.CaptionHeight()+y_gap))
      return(false);
   text_edit.SetValue(string(150));
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(w_number,text_edit);
   return(true);
}

また、このウィンドウのUI要素の最後のカテゴリには、[Buy](買う)と[Sell](売る)の2つのボタンが含まれています。ボタン追加メソッドは、CreateBuyButton()CreateSellButton()です。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateBuyButton(CWindow &window,CButton &button,string text,int x_gap,int y_gap,int w_number)
{
//--- Store the window pointer
   button.MainPointer(window);
   color baseclr=C'88,212,210';
//--- Set properties before creation
   button.XSize(120);
   button.YSize(40);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(baseclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(baseclr);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create a control element
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(w_number,button);
   return(true);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreateSellButton(CWindow &window,CButton &button,string text,int x_gap,int y_gap,int w_number)
{
//--- Store the window pointer
   button.MainPointer(window);
   color baseclr=C'236,85,79';
//--- Set properties before creation
   button.XSize(120);
   button.YSize(40);
   button.Font(m_base_font);
   button.FontSize(m_base_font_size);
   button.BackColor(baseclr);
   button.BackColorHover(baseclr);
   button.BackColorPressed(baseclr);
   button.BorderColor(baseclr);
   button.BorderColorHover(baseclr);
   button.BorderColorPressed(baseclr);
   button.LabelColor(clrWhite);
   button.LabelColorPressed(clrWhite);
   button.LabelColorHover(clrWhite);
   button.IsCenterText(true);
//--- Create a control element
   if(!button.CreateButton(text,x_gap,y_gap))
      return(false);
//--- Add a pointer to the element to the database
   CWndContainer::AddToElementsArray(w_number,button);
   return(true);
}

2つのボタンを追加して、CreateMarketWindow()メソッドの実装を完了します。

//+------------------------------------------------------------------+
//| Market order creation and editing window                         |
//+------------------------------------------------------------------+
bool CFastTrading::CreateMarketOrdersWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_orders_windows[0]);
//--- Properties
   m_orders_windows[0].XSize(450);
   m_orders_windows[0].YSize(242+58);
//--- Coordinates
   int x=m_order_button[0].XGap();
   int y=m_order_button[0].YGap()+60;
//---
   color clrmain=C'87,128,255';
//---
   m_orders_windows[0].CaptionHeight(22);
   m_orders_windows[0].IsMovable(true);
   m_orders_windows[0].CaptionColor(clrmain);
   m_orders_windows[0].CaptionColorLocked(clrmain);
   m_orders_windows[0].CaptionColorHover(clrmain);
   m_orders_windows[0].BackColor(m_background_color);
   m_orders_windows[0].BorderColor(clrmain);
   m_orders_windows[0].FontSize(m_base_font_size);
   m_orders_windows[0].Font(m_base_font);
   m_orders_windows[0].WindowType(W_DIALOG);
//--- Create the form
   if(!m_orders_windows[0].CreateWindow(m_chart_id,m_subwin,CAPTION_M_ORD_NAME,x,y))
      return(false);
//--- BUY BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[0],10,20,BUY_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[0],20,30,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[1],20+80+20,30,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[2],20+(80+20)*2,30,SL,1))
      return(false);
//--- Toggle buttons
   for(int i=0; i<3; i++)
      if(!CreateSwitchButton(m_orders_windows[0],m_switch_button[i],"-",20+(80+20)*i,60,1))
         return(false);
//--- Edits
   if(!CreateLotEdit(m_orders_windows[0],m_lot_edit[0],20,60+34,1))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[0],m_tp_edit[0],20+(80+20),60+34,1))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[0],m_sl_edit[0],20+(80+20)*2,60+34,1))
      return(false);
//--- The Buy button
   if(!CreateBuyButton(m_orders_windows[0],m_buy_execute,BUY+"(B)",m_orders_windows[0].XSize()-(120+20),103,1))
      return(false);
//--- SELL BLOCK
   if(!CreateFrame(m_orders_windows[0],m_frame[1],10,160,SELL_ORDER,1))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[3],20,170,LOT,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[4],20+80+20,170,TP,1))
      return(false);
   if(!CreateLabel(m_orders_windows[0],m_m_text_labels[5],20+(80+20)*2,170,SL,1))
      return(false);
//--- Toggle buttons
   for(int i=3; i<6; i++)
      if(!CreateSwitchButton(m_orders_windows[0],m_switch_button[i],"-",20+(80+20)*(i-3),170+30,1))
         return(false);
//--- Edits
   if(!CreateLotEdit(m_orders_windows[0],m_lot_edit[1],20,170+30+35,1))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[0],m_tp_edit[1],20+80+20,170+30+35,1))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[0],m_sl_edit[1],20+(80+20)*2,170+30+35,1))
      return(false);
//--- The Sell button
   if(!CreateSellButton(m_orders_windows[0],m_sell_execute,SELL+"(S)",m_orders_windows[0].XSize()-(120+20),242,1))
      return(false);
   return(true);
}

2つの新しいマクロ置換を追加することを忘れないでください。

#define BUY                            (m_language==RUSSIAN ? "Купить" : "Buy")
#define SELL                           (m_language==RUSSIAN ? "Продать" : "Sell")

この段階でプロジェクトをコンパイルし、結果を確認します。

図8 成行注文作成ウィンドウのインターフェイス

今のところ、これは単なるテンプレートです。テンプレートをさらに開発するには、次のタスクを実装する必要があります。

ボタン切り替えメカニズムの実装を開始して名前を変更する前に、デフォルト値を設定する必要があります。図8は、ボタンにダッシュのみがあることを示しています。名前を設定するにはSetButtonParam()メソッドを追加します。後ほど同じメソッドを使用して名前を切り替えます。

//+------------------------------------------------------------------+
//| Setting the button text                                          |
//+------------------------------------------------------------------+
void CFastTrading::SetButtonParam(CButton &button,string text)
{
   button.LabelText(text);
   button.Update(true);
}

イベントハンドラに移動し、インターフェイスの作成が完了したらイベントセクションを追加します。そこで、SetButtonParam()メソッドを使用してスイッチボタンの名前を設定します。

//--- UI creation completion
   if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI)
   {
      //---
      SetButtonParam(m_switch_button[0],LOT);
      SetButtonParam(m_switch_button[1],POINTS);
      SetButtonParam(m_switch_button[2],POINTS);
      SetButtonParam(m_switch_button[3],LOT);
      SetButtonParam(m_switch_button[4],POINTS);
      SetButtonParam(m_switch_button[5],POINTS);
   }

ボタン名のマクロ置換がもう1つあるので、Defines.mqhに追加します。

#define POINTS                         (m_language==RUSSIAN ? "Пункты" : "Points")

切り替えメカニズムを作成する準備が整いました。ButtonSwitch()関数は、ボタンの状態(押されている/いない)を追跡し、それに応じてボタン名を変更します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::ButtonSwitch(CButton &button,long lparam,string state1,string state2)
{
   if(lparam==button.Id())
   {
      if(!button.IsPressed())
         SetButtonParam(button,state1);
      else
         SetButtonParam(button,state2);
   }
}

ボタンクリックイベントによって名前が切り替わるため、イベントハンドラセクションで作成されたメソッドを呼び出します。

//--- Pressing the button event
   if(id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON)
   {
      //---
      if(lparam==m_order_button[0].Id())
         m_orders_windows[0].OpenWindow();
      //---
      if(lparam==m_order_button[1].Id())
         m_orders_windows[1].OpenWindow();
      //---
      ButtonSwitch(m_switch_button[0],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_switch_button[1],lparam,POINTS,PRICE);
      ButtonSwitch(m_switch_button[2],lparam,POINTS,PRICE);
      ButtonSwitch(m_switch_button[3],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_switch_button[4],lparam,POINTS,PRICE);
      ButtonSwitch(m_switch_button[5],lparam,POINTS,PRICE);
   }

また、両方の言語で新しいマクロ置換について説明します。

#define PERC_DEPO                      (m_language==RUSSIAN ? "% Депозит" : "% Deposit")
#define PRICE                          (m_language==RUSSIAN ? "Цена" : "Price")

プロジェクトを再度コンパイルすると、クリックによってボタン名が変わるようになります。

図9 切り替えボタンの名前変更

次へ移りましょう。次のタスクは、対応する切り替えボタンの状態に応じて、入力フィールドのプロパティを変更することです。これをおこなうには、入力フィールドごとにLotMarketSwitch()、TakeMarketSwitch()、StopMarketSwitch()の3つの新しいメソッドを追加します。最初のメソッドでは、ロット値はアカウント残高のパーセント切り替えられます。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::LotMarketSwitch(long lparam)
{
   for(int i=0; i<2; i++)
   {
      if(lparam==m_switch_button[i*3].Id())
      {
         if(m_switch_button[i*3].IsPressed())
         {
            m_lot_edit[i].SetDigits(0);
            m_lot_edit[i].StepValue(1);
            m_lot_edit[i].MaxValue(100);
            m_lot_edit[i].MinValue(1);
            m_lot_edit[i].SetValue(string(2));
            m_lot_edit[i].GetTextBoxPointer().Update(true);
         }
         else
         {
            m_lot_edit[i].SetDigits(2);
            m_lot_edit[i].StepValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP));
            m_lot_edit[i].MinValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN));
            m_lot_edit[i].MaxValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX));
            m_lot_edit[i].SetValue(string(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN)));
            m_lot_edit[i].GetTextBoxPointer().Update(true);
         }
      }
   }
}

他の2つのメソッドでは、レベル値がポイントから価格に切り替えられます。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::TakeMarketSwitch(long lparam)
{
   for(int i=0; i<2; i++)
   {
      if(lparam==m_switch_button[3*i+1].Id())
      {
         if(m_switch_button[3*i+1].IsPressed())
         {
            MqlTick tick;
            if(SymbolInfoTick(Symbol(),tick))
            {
               m_tp_edit[i].SetDigits(_Digits);
               m_tp_edit[i].StepValue(_Point);
               m_tp_edit[i].SetValue(string(tick.ask));
               m_tp_edit[i].GetTextBoxPointer().Update(true);
            }
         }
         else
         {
            m_tp_edit[i].SetDigits(0);
            m_tp_edit[i].StepValue(1);
            m_tp_edit[i].SetValue(string(150));
            m_tp_edit[i].GetTextBoxPointer().Update(true);
         }
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::StopMarketSwitch(long lparam)
{
   for(int i=0; i<2; i++)
   {
      if(lparam==m_switch_button[3*i+2].Id())
      {
         if(m_switch_button[3*i+2].IsPressed())
         {
            MqlTick tick;
            if(SymbolInfoTick(Symbol(),tick))
            {
               m_sl_edit[i].SetDigits(_Digits);
               m_sl_edit[i].StepValue(_Point);
               m_sl_edit[i].SetValue(string(tick.bid));
               m_sl_edit[i].GetTextBoxPointer().Update(true);
            }
         }
         else
         {
            m_sl_edit[i].SetDigits(0);
            m_sl_edit[i].StepValue(1);
            m_sl_edit[i].SetValue(string(150));
            m_sl_edit[i].GetTextBoxPointer().Update(true);
         }
      }
   }
}

次に、イベントハンドラーのボタンクリックイベントセクションで、3つのメソッドすべてを呼び出します。

      // --- Switch Lot/Percent of balance
      LotMarketSwitch(lparam);
      //--- Switch Take Profit Points/Price
      TakeMarketSwitch(lparam);
      //--- Switch Stop Loss Points/Price
      StopMarketSwitch(lparam);

結果を確認します。

図10 成行注文ウィンドウの入力フィールドのモードの切り替え

最後のタスクは、ボタンまたはホットキーを使用して、設定と入力フィールド値に従って成行注文を出せるようにすることです。この目的のために、3つの新しいメソッドを作成します。

基本クラスCFastTradingのprivateセクションで作成し、同じクラスに実装します。

//+------------------------------------------------------------------+
//| Trading Environment Initialization                               |
//+------------------------------------------------------------------+
void CFastTrading::OnInitTrading()
{
   string array_used_symbols[];
//--- Fill in the array of used symbols
   CreateUsedSymbolsArray(SYMBOLS_MODE_CURRENT,"",array_used_symbols);
//--- Set the type of the used symbol list in the symbol collection and fill in the list of symbol timeseries
   m_trade.SetUsedSymbols(array_used_symbols);
//--- Pass all existing collections to the trading class
   m_trade.TradingOnInit();
   m_trade.TradingSetMagic(m_magic_number);
   m_trade.TradingSetLogLevel(LOG_LEVEL_ERROR_MSG);
//--- Set synchronous passing of orders for all used symbols
   m_trade.TradingSetAsyncMode(false);
//--- Set correct order expiration and filling types to all trading objects
   m_trade.TradingSetCorrectTypeExpiration();
   m_trade.TradingSetCorrectTypeFilling();
}

クラスコンストラクタでこのメソッドを呼び出します。

//+------------------------------------------------------------------+
//| Constructor                                                      |
//+------------------------------------------------------------------+
CFastTrading::CFastTrading(void)
{
   OnInitTrading();
}

取引関数を実装する前に、それらが2つの異なるイベントで実行されることに注意してください

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetBuyOrder(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buy_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_B))
   {
      //---
      double lot;
      if(m_switch_button[0].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[0].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[0].GetValue()));
      if(m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[0].GetValue());
         double sl=double(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(!m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[0].GetValue());
         int sl=int(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(m_switch_button[1].IsPressed() && !m_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[0].GetValue());
         int sl=int(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(!m_switch_button[1].IsPressed() && m_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[0].GetValue());
         double sl=double(m_sl_edit[0].GetValue());
         if(m_trade.OpenBuy(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetSellOrder(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_sell_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_S))
   {
      //---
      double lot;
      if(m_switch_button[3].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[1].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[1].GetValue()));
      //---
      if(m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[1].GetValue());
         double sl=double(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(!m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[1].GetValue());
         int sl=int(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(!m_switch_button[4].IsPressed() && m_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[1].GetValue());
         double sl=double(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
      else if(m_switch_button[4].IsPressed() && !m_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[1].GetValue());
         int sl=int(m_sl_edit[1].GetValue());
         if(m_trade.OpenSell(lot,Symbol(),m_magic_number,sl,tp))
            return(true);
      }
   }
   return(false);
}

イベントハンドラでは両方の取引メソッドは呼び出されますが、上記の理由により、イベントを識別するセクションの外にあります。上記の関数の現在の実装では、LotPercent()メソッドを使用して、ロットサイズを残高のパーセントとして計算しています。 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CFastTrading::LotPercent(string symbol,ENUM_ORDER_TYPE trade_type,double price,double percent)
{
   double margin=0.0;
//--- checks
   if(symbol=="" || price<=0.0 || percent<1 || percent>100)
      return(0.0);
//--- calculate margin requirements for 1 lot
   if(!OrderCalcMargin(trade_type,symbol,1.0,price,margin) || margin<0.0)
      return(0.0);
//---
   if(margin==0.0)
      return(0.0);
//--- calculate maximum volume
   double volume=NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)*percent/100.0/margin,2);
//--- normalize and check limits
   double stepvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_STEP);
   if(stepvol>0.0)
      volume=stepvol*MathFloor(volume/stepvol);
//---
   double minvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MIN);
   if(volume<minvol)
      volume=0.0;
//---
   double maxvol=SymbolInfoDouble(symbol,SYMBOL_VOLUME_MAX);
   if(volume>maxvol)
      volume=maxvol;
//--- return volume
   return(volume);
}

成行注文の操作に関する部分の準備ができたので、指値注文を作成するためのウィンドウに移りましょう。成行注文で完了したのと同じ手順に従って、インターフェイスを作成します。ほとんどの手順は似ていますが、少しだけ詳細を説明します。

//+------------------------------------------------------------------+
//| Pending order creation and editing window                        |
//+------------------------------------------------------------------+
bool CFastTrading::CreatePendingOrdersWindow(void)
{
//--- Add a window pointer to the window array
   CWndContainer::AddWindow(m_orders_windows[1]);
//--- Properties
   m_orders_windows[1].XSize(600);
   m_orders_windows[1].YSize(580);
//--- Coordinates
   int x=m_order_button[0].XGap();
   int y=m_order_button[0].YGap()+60;
//---
   color clrmain=C'31,209,111';
//---
   m_orders_windows[1].CaptionHeight(22);
   m_orders_windows[1].IsMovable(true);
   m_orders_windows[1].CaptionColor(clrmain);
   m_orders_windows[1].CaptionColorLocked(clrmain);
   m_orders_windows[1].CaptionColorHover(clrmain);
   m_orders_windows[1].BackColor(m_background_color);
   m_orders_windows[1].BorderColor(clrmain);
   m_orders_windows[1].FontSize(m_base_font_size);
   m_orders_windows[1].Font(m_base_font);
   m_orders_windows[1].WindowType(W_DIALOG);
//--- Create the form
   if(!m_orders_windows[1].CreateWindow(m_chart_id,m_subwin,CAPTION_P_ORD_NAME,x,y))
      return(false);
//---BUY-STOP BLOCK
   if(!CreateFrame(m_orders_windows[1],m_frame[2],10,20,BUYSTOP_ORDER,2))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[0],20,60,PRICE,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[1],20+80+20,30,LOT,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[2],20+(80+20)*2,30,TP,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[3],20+(80+20)*3,30,SL,2))
      return(false);
//--- Switches
   for(int i=0; i<3; i++)
      if(!CreateSwitchButton(m_orders_windows[1],m_p_switch_button[i],"-",120+(80+20)*i,60,2))
         return(false);
//--- Edits
   if(!CreatePriceEdit(m_orders_windows[1],m_pr_edit[0],20,60+35,2))
      return(false);
   if(!CreateLotEdit(m_orders_windows[1],m_lot_edit[2],20+(80+20),60+35,2))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[1],m_tp_edit[2],20+(80+20)*2,60+35,2))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[1],m_sl_edit[2],20+(80+20)*3,60+35,2))
      return(false);
//--- Buy Stop placing button
   if(!CreateBuyButton(m_orders_windows[1],m_buystop_execute,"Buy Stop ( 1 )",m_orders_windows[1].XSize()-(120+20),103,2))
      return(false);
//---SELL-STOP BLOCK
   if(!CreateFrame(m_orders_windows[1],m_frame[3],10,160,SELLSTOP_ORDER,2))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[4],20,170+30,PRICE,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[5],20+80+20,170,LOT,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[6],20+(80+20)*2,170,TP,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[7],20+(80+20)*3,170,SL,2))
      return(false);
//--- Switches
   for(int i=3; i<6; i++)
      if(!CreateSwitchButton(m_orders_windows[1],m_p_switch_button[i],"-",120+(80+20)*(i-3),170+30,2))
         return(false);
//--- Edits
   if(!CreatePriceEdit(m_orders_windows[1],m_pr_edit[1],20,170+30+35,2))
      return(false);
   if(!CreateLotEdit(m_orders_windows[1],m_lot_edit[3],20+(80+20),170+30+35,2))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[1],m_tp_edit[3],20+(80+20)*2,170+30+35,2))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[1],m_sl_edit[3],20+(80+20)*3,170+30+35,2))
      return(false);
//--- Sell Stop placing button
   if(!CreateSellButton(m_orders_windows[1],m_sellstop_execute,"Sell Stop ( 2 )",m_orders_windows[1].XSize()-(120+20),242,2))
      return(false);
//---BUY-LIMIT BLOCK
   if(!CreateFrame(m_orders_windows[1],m_frame[4],10,300,BUYLIMIT_ORDER,2))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[8],20,330,PRICE,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[9],20+80+20,310,LOT,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[10],20+(80+20)*2,310,TP,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[11],20+(80+20)*3,310,SL,2))
      return(false);
//--- Switches
   for(int i=6; i<9; i++)
      if(!CreateSwitchButton(m_orders_windows[1],m_p_switch_button[i],"-",120+(80+20)*(i-6),330,2))
         return(false);
//--- Edits
   if(!CreatePriceEdit(m_orders_windows[1],m_pr_edit[2],20,365,2))
      return(false);
   if(!CreateLotEdit(m_orders_windows[1],m_lot_edit[4],20+(80+20),365,2))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[1],m_tp_edit[4],20+(80+20)*2,365,2))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[1],m_sl_edit[4],20+(80+20)*3,365,2))
      return(false);
//--- Buy Limit placing button
   if(!CreateBuyButton(m_orders_windows[1],m_buylimit_execute,"Buy Limit ( 3 )",m_orders_windows[1].XSize()-(120+20),382,2))
      return(false);
//---SELL-LIMIT BLOCK
   if(!CreateFrame(m_orders_windows[1],m_frame[5],10,440,SELLLIMIT_ORDER,2))
      return(false);
//--- Headers
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[12],20,470,PRICE,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[13],20+80+20,450,LOT,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[14],20+(80+20)*2,450,TP,2))
      return(false);
   if(!CreateLabel(m_orders_windows[1],m_p_text_labels[15],20+(80+20)*3,450,SL,2))
      return(false);
//--- Switches
   for(int i=9; i<12; i++)
      if(!CreateSwitchButton(m_orders_windows[1],m_p_switch_button[i],"-",120+(80+20)*(i-9),470,2))
         return(false);
//--- Edits
   if(!CreatePriceEdit(m_orders_windows[1],m_pr_edit[3],20,505,2))
      return(false);
   if(!CreateLotEdit(m_orders_windows[1],m_lot_edit[5],20+(80+20),505,2))
      return(false);
   if(!CreateTakeProfitEdit(m_orders_windows[1],m_tp_edit[5],20+(80+20)*2,505,2))
      return(false);
   if(!CreateStopLossEdit(m_orders_windows[1],m_sl_edit[5],20+(80+20)*3,505,2))
      return(false);
//--- Sell Limit placing button
   if(!CreateSellButton(m_orders_windows[1],m_selllimit_execute,"Sell Limit ( 4 )",m_orders_windows[1].XSize()-(120+20),522,2))
      return(false);
//---
   return(true);
}

ご覧のとおり、上記のコードは、成行注文ウィンドウで使用したのと同じメソッドを使用しています。ただし、新しいメソッドが1つあります。CreatePriceEdit()は、指値注文値の入力フィールドです。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::CreatePriceEdit(CWindow &window,CTextEdit &text_edit,const int x_gap,const int y_gap,int w_number)
{
//--- Store the pointer to the main control
   text_edit.MainPointer(window);
//--- Properties
   text_edit.XSize(80);
   text_edit.YSize(24);
   text_edit.Font(m_base_font);
   text_edit.FontSize(m_base_font_size);
   text_edit.StepValue(_Point);
   text_edit.SpinEditMode(true);
   text_edit.SetDigits(_Digits);
   text_edit.GetTextBoxPointer().XGap(1);
   text_edit.GetTextBoxPointer().XSize(80);
//--- Create a control element
   if(!text_edit.CreateTextEdit("",x_gap,window.CaptionHeight()+y_gap))
      return(false);
//---
   MqlTick tick;
   if(SymbolInfoTick(Symbol(),tick))
      text_edit.SetValue(string(tick.bid));
//--- Add the object to the common array of object groups
   CWndContainer::AddToElementsArray(w_number,text_edit);
   return(true);
}

最初のテンプレートはメソッドの実装後に準備ができていますが、インターフェイスはまだ使用できません。構成する必要があります。この部分を同じ順序で実装します。切り替えボタンを構成してそれらの状態を入力フィールドプロパティに接続し、指値注文を出すための関数を作成します。

OnEvent()ハンドラのインターフェイス作成完了セクションに移動して、切り替えボタンの名前を設定します。

//--- UI creation completion
   if(id==CHARTEVENT_CUSTOM+ON_END_CREATE_GUI)
   {
      //---
      SetButtonParam(m_switch_button[0],LOT);
      SetButtonParam(m_switch_button[1],POINTS);
      SetButtonParam(m_switch_button[2],POINTS);
      SetButtonParam(m_switch_button[3],LOT);
      SetButtonParam(m_switch_button[4],POINTS);
      SetButtonParam(m_switch_button[5],POINTS);
      //---
      SetButtonParam(m_p_switch_button[0],LOT);
      SetButtonParam(m_p_switch_button[1],POINTS);
      SetButtonParam(m_p_switch_button[2],POINTS);
      SetButtonParam(m_p_switch_button[3],LOT);
      SetButtonParam(m_p_switch_button[4],POINTS);
      SetButtonParam(m_p_switch_button[5],POINTS);
      SetButtonParam(m_p_switch_button[6],LOT);
      SetButtonParam(m_p_switch_button[7],POINTS);
      SetButtonParam(m_p_switch_button[8],POINTS);
      SetButtonParam(m_p_switch_button[9],LOT);
      SetButtonParam(m_p_switch_button[10],POINTS);
      SetButtonParam(m_p_switch_button[11],POINTS);
   }

ボタンクリックイベントセクションに移動して、ボタンの状態を切り替えて名前を変更するメカニズムを実装します。

      //---
      ButtonSwitch(m_p_switch_button[0],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_p_switch_button[1],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[2],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[3],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_p_switch_button[4],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[5],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[6],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_p_switch_button[7],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[8],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[9],lparam,LOT,PERC_DEPO);
      ButtonSwitch(m_p_switch_button[10],lparam,POINTS,PRICE);
      ButtonSwitch(m_p_switch_button[11],lparam,POINTS,PRICE);

切り替えボタンを入力フィールドとそのプロパティにリンクするには、LotPendingSwitch()TakePendingSwitch()StopPendingSwitch()の3つの新しいメソッドを作成します。  

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::LotPendingSwitch(long lparam)
{
   for(int i=0; i<4; i++)
   {
      if(lparam==m_p_switch_button[3*i].Id())
      {
         if(m_p_switch_button[3*i].IsPressed())
         {
            m_lot_edit[i+2].SetDigits(0);
            m_lot_edit[i+2].StepValue(1);
            m_lot_edit[i+2].MaxValue(100);
            m_lot_edit[i+2].MinValue(1);
            m_lot_edit[i+2].SetValue(string(2));
            m_lot_edit[i+2].GetTextBoxPointer().Update(true);
         }
         else
         {
            m_lot_edit[i+2].SetDigits(2);
            m_lot_edit[i+2].StepValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP));
            m_lot_edit[i+2].MinValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN));
            m_lot_edit[i+2].MaxValue(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX));
            m_lot_edit[i+2].SetValue(string(SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN)));
            m_lot_edit[i+2].GetTextBoxPointer().Update(true);
         }
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::TakePendingSwitch(long lparam)
{
   for(int i=0; i<4; i++)
   {
      if(lparam==m_p_switch_button[3*i+1].Id())
      {
         if(m_p_switch_button[3*i+1].IsPressed())
         {
            MqlTick tick;
            if(SymbolInfoTick(Symbol(),tick))
            {
               m_tp_edit[i+2].SetDigits(_Digits);
               m_tp_edit[i+2].StepValue(_Point);
               m_tp_edit[i+2].SetValue(string(tick.ask));
               m_tp_edit[i+2].GetTextBoxPointer().Update(true);
            }
         }
         else
         {
            m_tp_edit[i+2].SetDigits(0);
            m_tp_edit[i+2].StepValue(1);
            m_tp_edit[i+2].SetValue(string(150));
            m_tp_edit[i+2].GetTextBoxPointer().Update(true);
         }
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::StopPendingSwitch(long lparam)
{
   for(int i=0; i<4; i++)
   {
      if(lparam==m_p_switch_button[3*i+2].Id())
      {
         if(m_p_switch_button[3*i+2].IsPressed())
         {
            MqlTick tick;
            if(SymbolInfoTick(Symbol(),tick))
            {
               m_sl_edit[i+2].SetDigits(_Digits);
               m_sl_edit[i+2].StepValue(_Point);
               m_sl_edit[i+2].SetValue(string(tick.bid));
               m_sl_edit[i+2].GetTextBoxPointer().Update(true);
            }
         }
         else
         {
            m_sl_edit[i+2].SetDigits(0);
            m_sl_edit[i+2].StepValue(1);
            m_sl_edit[i+2].SetValue(string(150));
            m_sl_edit[i+2].GetTextBoxPointer().Update(true);
         }
      }
   }
}

ボタンクリックイベントハンドラセクションで呼び出します。

      // --- Switch Lot/Percent of balance
      LotPendingSwitch(lparam);
      //--- Switch Take Profit Points/Price
      TakePendingSwitch(lparam);
      //--- Switch Stop Loss Points/Price
      StopPendingSwitch(lparam);

プロジェクトをコンパイルして結果を確認します。

図11 指値注文ウィンドウの入力フィールドのモードの切り替え

入力フィールドモードスイッチの準備ができました。 プロパティの変更も機能しています。指値注文を出すために必要な関数の作成に進みます。アルゴリズムは成行注文に似ています。タイプごとに1つずつ、合計4つのメソッドを作成します。

   bool              SetBuyStopOrder(int id,long lparam);
   bool              SetSellStopOrder(int id,long lparam);
   bool              SetBuyLimitOrder(int id,long lparam);
   bool              SetSellLimitOrder(int id,long lparam);

実装します。指値注文ごとにホットキーボタンのクリックを設定します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetBuyStopOrder(int id,long lparam)
{
   if(!m_orders_windows[1].IsVisible())
      return(false);
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buystop_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_1))
   {
      //---
      double lot;
      if(m_p_switch_button[0].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[2].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[2].GetValue()));
      //---
      double pr=double(m_pr_edit[0].GetValue());
      //---
      if(m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[2].GetValue());
         double sl=double(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[2].GetValue());
         int sl=int(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(m_p_switch_button[1].IsPressed() && !m_p_switch_button[2].IsPressed())
      {
         double tp=double(m_tp_edit[2].GetValue());
         int sl=int(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[1].IsPressed() && m_p_switch_button[2].IsPressed())
      {
         int tp=int(m_tp_edit[2].GetValue());
         double sl=double(m_sl_edit[2].GetValue());
         if(m_trade.PlaceBuyStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetSellStopOrder(int id,long lparam)
{
   if(!m_orders_windows[1].IsVisible())
      return(false);
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_sellstop_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_2))
   {
      //---
      double lot;
      if(m_p_switch_button[3].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[3].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[3].GetValue()));
      //---
      double pr=double(m_pr_edit[1].GetValue());
      //---
      if(m_p_switch_button[4].IsPressed() && m_p_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[3].GetValue());
         double sl=double(m_sl_edit[3].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[4].IsPressed() && !m_p_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[3].GetValue());
         int sl=int(m_sl_edit[3].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(m_p_switch_button[4].IsPressed() && !m_p_switch_button[5].IsPressed())
      {
         double tp=double(m_tp_edit[3].GetValue());
         int sl=int(m_sl_edit[3].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[4].IsPressed() && m_p_switch_button[5].IsPressed())
      {
         int tp=int(m_tp_edit[3].GetValue());
         double sl=double(m_sl_edit[3].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetBuyLimitOrder(int id,long lparam)
{
   if(!m_orders_windows[1].IsVisible())
      return(false);
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_buylimit_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_3))
   {
      //---
      double lot;
      if(m_p_switch_button[6].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_BUY,SymbolInfoDouble(Symbol(),SYMBOL_ASK),StringToDouble(m_lot_edit[4].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[4].GetValue()));
      //---
      double pr=double(m_pr_edit[2].GetValue());
      //---
      if(m_p_switch_button[7].IsPressed() && m_p_switch_button[8].IsPressed())
      {
         double tp=double(m_tp_edit[4].GetValue());
         double sl=double(m_sl_edit[4].GetValue());
         if(m_trade.PlaceBuyLimit(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[7].IsPressed() && !m_p_switch_button[8].IsPressed())
      {
         int tp=int(m_tp_edit[4].GetValue());
         int sl=int(m_sl_edit[4].GetValue());
         if(m_trade.PlaceBuyLimit(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(m_p_switch_button[7].IsPressed() && !m_p_switch_button[8].IsPressed())
      {
         double tp=double(m_tp_edit[4].GetValue());
         int sl=int(m_sl_edit[4].GetValue());
         if(m_trade.PlaceBuyLimit(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[7].IsPressed() && m_p_switch_button[8].IsPressed())
      {
         int tp=int(m_tp_edit[4].GetValue());
         double sl=double(m_sl_edit[4].GetValue());
         if(m_trade.PlaceBuyLimit(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
   }
   return(false);
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool CFastTrading::SetSellLimitOrder(int id,long lparam)
{
   if(!m_orders_windows[1].IsVisible())
      return(false);
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_selllimit_execute.Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_4))
   {
      //---
      double lot;
      if(m_p_switch_button[9].IsPressed())
         lot=LotPercent(Symbol(),ORDER_TYPE_SELL,SymbolInfoDouble(Symbol(),SYMBOL_BID),StringToDouble(m_lot_edit[5].GetValue()));
      else
         lot=NormalizeLot(Symbol(),StringToDouble(m_lot_edit[5].GetValue()));
      //---
      double pr=double(m_pr_edit[3].GetValue());
      //---
      if(m_p_switch_button[10].IsPressed() && m_p_switch_button[11].IsPressed())
      {
         double tp=double(m_tp_edit[5].GetValue());
         double sl=double(m_sl_edit[5].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[10].IsPressed() && !m_p_switch_button[11].IsPressed())
      {
         int tp=int(m_tp_edit[5].GetValue());
         int sl=int(m_sl_edit[5].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(m_p_switch_button[10].IsPressed() && !m_p_switch_button[11].IsPressed())
      {
         double tp=double(m_tp_edit[5].GetValue());
         int sl=int(m_sl_edit[5].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
      else if(!m_p_switch_button[10].IsPressed() && m_p_switch_button[11].IsPressed())
      {
         int tp=int(m_tp_edit[5].GetValue());
         double sl=double(m_sl_edit[5].GetValue());
         if(m_trade.PlaceSellStop(lot,Symbol(),pr,sl,tp,m_magic_number))
            return(true);
      }
   }
   return(false);
}

次に、イベントハンドラに移動し、新しく作成されたメソッドの呼び出しを追加します

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//---
   SetBuyOrder(id,lparam);
   SetSellOrder(id,lparam);
//---
   SetBuyStopOrder(id,lparam);
   SetSellStopOrder(id,lparam);
   SetBuyLimitOrder(id,lparam);
   SetSellLimitOrder(id,lparam);

すべての注文タイプを処理するための基本的な機能が用意されています。このアプリケーションのの最終的な目的は手動取引で最大の利便性とスピードを提供することなので、小さな機能を追加して成行注文と指値注文をより速くすることにしました。その原理は次のとおりです。異なるモードで入力フィールド値を設定する場合、上下の矢印を使用して指定されたステップで値を変更できますが、たとえば指値注文価格を設定する場合に矢印を押すと、EURUSDの価格が1.08500から1.85001に変更されます。これでは遅くてあまり便利ではありません。入力フィールドを編集用に選択してから上/下のホットキーを押したときに、値の変更ステップが10倍になるようにします。この目的のために、ArrowSwitch()メソッドを作成します。

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::ArrowSwitch(long lparam)
{
//--- Prices
   for(int i=0; i<4; i++)
   {
      if(m_pr_edit[i].GetTextBoxPointer().TextEditState())
      {
         if(lparam==KEY_UP)
         {
            //--- Get the new value
            double value=StringToDouble(m_pr_edit[i].GetValue())+m_pr_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_pr_edit[i].SetValue(DoubleToString(value),false);
         }
         else if(lparam==KEY_DOWN)
         {
            //--- Get the new value
            double value=StringToDouble(m_pr_edit[i].GetValue())-m_pr_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_pr_edit[i].SetValue(DoubleToString(value),false);
         }
      }
   }
//--- Lot
   for(int i=0; i<6; i++)
   {
      if(m_lot_edit[i].GetTextBoxPointer().TextEditState())
      {
         if(lparam==KEY_UP)
         {
            //--- Get the new value
            double value=StringToDouble(m_lot_edit[i].GetValue())+m_lot_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_lot_edit[i].SetValue(DoubleToString(value),false);
         }
         else if(lparam==KEY_DOWN)
         {
            //--- Get the new value
            double value=StringToDouble(m_lot_edit[i].GetValue())-m_lot_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_lot_edit[i].SetValue(DoubleToString(value),false);
         }
      }
   }
//--- Take Profit, Stop Loss
   for(int i=0; i<6; i++)
   {
      //---
      if(m_tp_edit[i].GetTextBoxPointer().TextEditState())
      {
         if(lparam==KEY_UP)
         {
            //--- Get the new value
            double value=StringToDouble(m_tp_edit[i].GetValue())+m_tp_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_tp_edit[i].SetValue(DoubleToString(value),false);
         }
         else if(lparam==KEY_DOWN)
         {
            //--- Get the new value
            double value=StringToDouble(m_tp_edit[i].GetValue())-m_tp_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_tp_edit[i].SetValue(DoubleToString(value),false);
         }
      }
      //---
      if(m_sl_edit[i].GetTextBoxPointer().TextEditState())
      {
         if(lparam==KEY_UP)
         {
            //--- Get the new value
            double value=StringToDouble(m_sl_edit[i].GetValue())+m_sl_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_sl_edit[i].SetValue(DoubleToString(value),false);
         }
         else if(lparam==KEY_DOWN)
         {
            //--- Get the new value
            double value=StringToDouble(m_sl_edit[i].GetValue())-m_sl_edit[i].StepValue()*10;
            //--- Increase by one step and check for exceeding the limit
            m_sl_edit[i].SetValue(DoubleToString(value),false);
         }
      }
   }
}

メソッドを、イベントハンドラのキー押下セクションで呼び出します。

//--- Keypress
   if(id==CHARTEVENT_KEYDOWN)
   {
      //---
      ArrowSwitch(lparam);
....

図12は、値変更速度の違いを示しています。

図12 ホットキーを使用した編集フィールドでの迅速な値の変更

市場注文および指値注文を迅速に出すためのツールの準備が整いました。次に、メインのアプリケーションウィンドウに移動して、既存注文に関連するアクションを追加します(記事冒頭の図を参照)。これには、収益性の高い注文をすべて決済する、損失をともなう注文をすべて決済する、既存の指値注文をすべて削除するという3つのアクションが含まれます。これらのアクションは、特定のマジックナンバーを持つアプリケーションによって行われた注文にのみ適用されます。また、現在のマジックナンバーで注文してからEAプロパティでマジックナンバーを変更する場合、古い番号を持つ既存の注文は現在のアプリケーションに関連しなくなるため、無視する必要があることにも注意してください。

これらのアクションを実装しましょう。3つの新しいメソッドを作成します。

   void              CloseAllMarketProfit(int id,long lparam);
   void              CloseAllMarketLoss(int id,long lparam);
   void              DeleteAllPending(int id,long lparam);

それぞれを実装します。 

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::CloseAllMarketProfit(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[2].Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_C))
   {
      //--- declare the request and the result
      MqlTradeRequest request;
      MqlTradeResult  result;
      int total=PositionsTotal(); // the number of open positions
      //--- iterate over open positions
      for(int i=total-1; i>=0; i--)
      {
         //--- order parameters
         ulong  position_ticket=PositionGetTicket(i);                                      // position ticket
         string position_symbol=PositionGetString(POSITION_SYMBOL);                        // symbol
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);              // the number of decimal places
         ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // position MagicNumber
         double volume=PositionGetDouble(POSITION_VOLUME);                                 // position volume
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);    // position type
         double profit=PositionGetDouble(POSITION_PROFIT);
         double swap=PositionGetDouble(POSITION_SWAP);
         //--- if MagicNumber matches
         if(magic==m_magic_number)
            if(position_symbol==Symbol())
               if(profit+swap>0)
               {
                  //--- zeroing the request and result values
                  ZeroMemory(request);
                  ZeroMemory(result);
                  //--- set the operation parameters
                  request.action   =TRADE_ACTION_DEAL;        // trading operation type
                  request.position =position_ticket;          // position ticket
                  request.symbol   =position_symbol;          // symbol
                  request.volume   =volume;                   // position volume
                  request.deviation=5;                        // allowable price deviation
                  request.magic    =m_magic_number;           // position MagicNumber
                  //--- Set order price and type depending on the position type
                  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;
                  }
                  //--- sending a request
                  if(!OrderSend(request,result))
                     PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
               }
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::CloseAllMarketLoss(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[3].Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_D))
   {
      //--- declare the request and the result
      MqlTradeRequest request;
      MqlTradeResult  result;
      ZeroMemory(request);
      ZeroMemory(result);
      int total=PositionsTotal(); // the number of open positions
      //--- iterate over open positions
      for(int i=total-1; i>=0; i--)
      {
         //--- order parameters
         ulong  position_ticket=PositionGetTicket(i);                                      // position ticket
         string position_symbol=PositionGetString(POSITION_SYMBOL);                        // symbol
         int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);              // the number of decimal places
         ulong  magic=PositionGetInteger(POSITION_MAGIC);                                  // position MagicNumber
         double volume=PositionGetDouble(POSITION_VOLUME);                                 // position volume
         ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);    // position type
         double profit=PositionGetDouble(POSITION_PROFIT);
         double swap=PositionGetDouble(POSITION_SWAP);
         //--- if MagicNumber matches
         if(magic==m_magic_number)
            if(position_symbol==Symbol())
               if(profit+swap<0)
               {
                  //--- zeroing the request and result values
                  ZeroMemory(request);
                  ZeroMemory(result);
                  //--- set the operation parameters
                  request.action   =TRADE_ACTION_DEAL;        // trading operation type
                  request.position =position_ticket;          // position ticket
                  request.symbol   =position_symbol;          // symbol
                  request.volume   =volume;                   // position volume
                  request.deviation=5;                        // allowable price deviation
                  request.magic    =m_magic_number;           // position MagicNumber
                  //--- Set order price and type depending on the position type
                  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;
                  }
                  //--- sending a request
                  if(!OrderSend(request,result))
                     PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
               }
      }
   }
}
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CFastTrading::DeleteAllPending(int id,long lparam)
{
   if((id==CHARTEVENT_CUSTOM+ON_CLICK_BUTTON && lparam==m_order_button[4].Id()) ||
         (id==CHARTEVENT_KEYDOWN && lparam==KEY_R))
   {
      //--- declare and initialize the trade request and result of trade request
      MqlTradeRequest request;
      MqlTradeResult  result;
      //--- iterate over all placed pending orders
      for(int i=OrdersTotal()-1; i>=0; i--)
      {
         ulong  order_ticket=OrderGetTicket(i);                   // order ticket
         ulong  magic=OrderGetInteger(ORDER_MAGIC);               // order MagicNumber
         //--- if MagicNumber matches
         if(magic==m_magic_number)
         {
            //--- zeroing the request and result values
            ZeroMemory(request);
            ZeroMemory(result);
            //--- set the operation parameters
            request.action= TRADE_ACTION_REMOVE;                  // trading operation type
            request.order = order_ticket;                         // order ticket
            //--- sending a request
            if(!OrderSend(request,result))
               PrintFormat("OrderSend error %d",GetLastError());  // if unable to send the request, output the error code
         }
      }
   }
}

作成されたメソッドは、メインアプリケーションウィンドウのボタンクリックおよびホットキー押下の2つの異なるイベントによってアクションを実行するためのルールにも準拠していることに注意してください。3つの関数はすべて、セクション外のイベントハンドラで呼び出されます

//+------------------------------------------------------------------+
//| Chart event handler                                              |
//+------------------------------------------------------------------+
void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam)
{
//---
   SetBuyOrder(id,lparam);
   SetSellOrder(id,lparam);
//---
   SetBuyStopOrder(id,lparam);
   SetSellStopOrder(id,lparam);
   SetBuyLimitOrder(id,lparam);
   SetSellLimitOrder(id,lparam);
//---
   CloseAllMarketProfit(id,lparam);
   CloseAllMarketLoss(id,lparam);
//---
   DeleteAllPending(id,lparam);

これで、クイック手動取引ツールキットの基本機能の開発が完了しました。以下のビデオは、作成されたアプリケーションを示しています。



終わりに

添付されたアーカイブには、リストされたすべてのファイルが含まれています。これらのファイルは、適切なフォルダにあります。正しく動作させるためには、MQL5フォルダをターミナルフォルダに保存するだけです。MQL5フォルダのあるルートディレクトリを開くには、MetaTrader 5ターミナルでCtrl+Shift+Dキーの組み合わせを押すか、下記の図13にあるようにコンテキストメニューを使用します。


図13 MetaTrader 5ターミナルルートでMQL5フォルダを開く