クイック手動取引ツールキット: 基本機能
内容
はじめに
今日、多くのトレーダーが自動取引システムに切り替えています。これらのシステムには、追加のセットアップが必要なものも完全に自動化されてすぐに使用できるものもあります。ただし、昔ながらの方法で手動で取引することを好むトレーダーもかなりいます。彼らは、特定の取引状況ごとに意思決定をおこなう際に、人間の専門家の判断を得るのを好みます。そのような状況は時折急速に発展するので、トレーダーは迅速に対応する必要があります。また、一部の取引スタイル(スキャルピングなど)では、注文を出すタイミングを正確にする必要があります。このようなときに、追加のツールが役立つ場合があります。これらのツールは、発注や決済やなどの目的のアクションを可能な限り最速で実装できます。そのため、迅速な手動取引のニーズに対応するための基本機能を実装することにしました。
ツールキットの概念
まず、手動取引で必要になる可能性のある一連の基本的なアクションを決定して、これに基づいて、適切なアクションを効率的かつ迅速に実行できるツールを開発します。手動取引には基礎となる取引システムがあります。これは、成行注文または指値注文のいずれかです。したがって、ツールキットの主な基準は、これら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 プロジェクトファイルの構造
作成したファイルの目的を考えてみましょう。
- SimpleTrading.mq5 - エキスパートアドバイザーのファイル。GUIが作成され、アプリケーションの初期設定が含まれます。
- Program.mqh — エキスパートアドバイザーに接続されるインクルードファイル。CFastTradingクラス、そのフィールドおよびメソッドが含まれます。また、部分的な実装も含まれます。
- MainWindow.mqh — Program.mqhに接続されるインクルードファイル。GUI要素の実装メソッドが含まれます。
- Defines.mqh — Program.mqhに接続されるインクルードファイル。英語版とロシア語版を実装するために使用されるGUI要素の一連のマクロ置換が含まれます。
まず、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を接続して、新しく作成されたクラスの場合はインスタンスを作成します。また、入力パラメータを設定します。これには次のものが含まれます。
- Base FontSize —アプリケーションの基本フォントサイズ。
- Caption Color — メインアプリケーションウィンドウのキャプションカラー。
- Back color — 背景色。
- Interface language — インターフェイス言語。
- Magic Number — このエキスパートアドバイザーによって作成された注文の一意の番号。
//+------------------------------------------------------------------+ //| 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つの新しいメソッドを作成します。
- OnInitTrading() — 取引アカウント環境を定義および設定する
- SetBuyOrder() — 成行買い注文を開く
- SetSellOrder() — 成行売り注文を開く
基本クラス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フォルダを開く
MetaQuotes Ltdによってロシア語から翻訳されました。
元の記事: https://www.mql5.com/ru/articles/7892
- 無料取引アプリ
- 8千を超えるシグナルをコピー
- 金融ニュースで金融マーケットを探索