如今,众多交易者切换至自动交易系统,这类系统可能需要附加设置,或是能够完全自动化并准备就绪。 然而,有相当一部分交易者更喜欢以旧有方式进行手动交易。 在各种特定交易情况下制定决策时,他们更期望拥有人类专家的判断力。 有时,这种状况会快速发展,因此交易者需要迅速对其做出反应。 而且,某些交易方式(例如,剥头皮)要求准确入场时机。 在其中,附加工具也许会派上用场:它们可为所需动作提供最快可能实施,诸如入场或离场。 因此,我决定实现基本功能,从而满足快速手动交易需求。赫兹股票量化软件
工具箱的概念
首先,有必要确定手动交易中可能需要的一组基本操作。 有基于此,我们将开发一种工具,能够高效、快捷地执行相应的操作。 手动交易已有一套底层交易系统,这意味着以下入场入方法之一:使用市价或挂单。 因此,该工具箱的主要准则是运用这两种类型订单的能力。 我们还可以为交易者选择在交易过程中可以执行的任务 — 工具可有助于减少执行这些任务时所需的时间和数量。赫兹股票量化软件
图例 1 工具箱主窗口
图例 1 显示两个类别:市价单和挂单。 我还选择了三个基本任务,这些任务有时需要快速执行,但无法在一个动作里一次性完成。 许多应用程序,包括 赫兹股票量化软件终端,都有一组基本的热键,可快速执行某些命令或操作。 我们的应用程序理应考虑这一事实。 每个热键显示在括号中 — 按下时,将执行指定的操作,或者 — 在处理订单时,将打开一个相应的窗口。 它也可以用鼠标执行操作。 例如,可以通过按 C 键或单击 “Close all profitable” 来把所有获利订单平仓。赫兹股票量化软件
按下 M 键,或单击 “Market order” 将打开 “Settings: Market order” 窗口。 该窗口包含入场买入或卖出订单的输入数据选项。 赫兹股票量化软件
图例 2 配置和创建市价订单的窗口。赫兹股票量化软件
除了基本设置外,与终端中的可用设置类赫兹股票量化软件似,不仅可选择手数作为数值,还可以选择账户余额的百分比。 这也涉及止盈和止损:不仅能以价位格式,还可以点数表示。 还可以通过两种方式执行“买入”和“卖出”操作:单击相应的按钮,或按下括号中指定的热键。 赫兹股票量化软件
按下 P 打开挂单设置窗口。 支持四种挂单类型。
图例 3 配置和创建挂单的窗口
与市价订单类似,挂单手数支持数值或余额百分比的形式,还可以选择价格或点数的止盈和止损。 赫兹股票量化软件
工具实现
首先,我们来创建一个初始项目结构。 打开 Experts 目录,创建 “Simple Trading” 文件夹及一些文件,如图例 4 所示。
图例 4 项目文件结构
我们研究一下所创建文件的作用:
- SimpleTrading.mq5 — 智能交易系统的文件,将在其中创建 GUI,并包含初始应用程序设置。
- Program.mqh — 包含要连接到 EA 的文件,该文件将包含 CFastTrading 类,及其字段和方法。 它还包含其部分实现。
- MainWindow.mqh — 连接的包含文件 Program.mqh ,内含 GUI 元素的实现方法。
- Defines.mqh — 连接的包含文件 Program.mqh ;内含一组 GUI 元素的宏替换,用于实现英语和俄语版本。赫兹股票量化软件
首先,打开 Program.mqh ,连接实现界面和交易功能所需的函数库,并创建 CFastTrading 类。
//+------------------------------------------------------------------+ //| Program.mqh | //| Alex2356 | //| https://www.mql5.com/zh/users/alex2356/seller | //+------------------------------------------------------------------+ #include <EasyAndFastGUI\WndEvents.mqh> #include <DoEasy25\Engine.mqh> #include "Defines.mqh" //+------------------------------------------------------------------+ //| 切换界面语言的枚举 | //+------------------------------------------------------------------+ enum LANG { RUSSIAN, // 俄语 ENGLISH // 英语 }; //+------------------------------------------------------------------+ //| 创建应用程序的类 | //+------------------------------------------------------------------+ class CFastTrading : public CWndEvents { public: CFastTrading(void); ~CFastTrading(void); //--- 初始化/逆初始化 void OnInitEvent(void); void OnDeinitEvent(const int reason); //--- 计时器 void OnTimerEvent(void); //--- 图表事件应答 virtual void OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam); }; //+------------------------------------------------------------------+ //| 加入 GUI 元素 | //+------------------------------------------------------------------+ #include "MainWindow.mqh" //+------------------------------------------------------------------+ //| 构造函数 | //+------------------------------------------------------------------+ CFastTrading::CFastTrading(void) { } //+------------------------------------------------------------------+ //| 析构函数 | //+------------------------------------------------------------------+ CFastTrading::~CFastTrading(void) { } //+------------------------------------------------------------------+ //| 初始化 | //+------------------------------------------------------------------+ void CFastTrading::OnInitEvent(void) { } //+------------------------------------------------------------------+ //| 逆初始化 | //+------------------------------------------------------------------+ void CFastTrading::OnDeinitEvent(const int reason) { //--- Remove the interface CWndEvents::Destroy(); } //+------------------------------------------------------------------+ //| 计时器 | //+------------------------------------------------------------------+ void CFastTrading::OnTimerEvent(void) { CWndEvents::OnTimerEvent(); //--- } //+------------------------------------------------------------------+ //| 图表事件应答 | //+------------------------------------------------------------------+ void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { } //+------------------------------------------------------------------+
现在,打开 EA 文件 SimpleTrading.mq5 ,把它连接到 Program.mqh ,若有新创建的类,则创建一个实例< /s3>。 此外,设置输入参数,其中包括:
- Base FontSize — 应用程序的基本字体大小。
- Caption Color — 主应用程序窗口的标题颜色。
- Back color — 背景颜色。
- Interface language — 界面语言。
- Magic Number — 本智能交易系统创建订单时的唯一识别码。
//+------------------------------------------------------------------+ //| SimpleTrading.mq5 | //| Alex2356 | //| https://www.mql5.com/zh/users/alex2356/seller | //+------------------------------------------------------------------+ #property copyright "Copyright 2020, Alexander Fedosov" #property link "https://www.mql5.com/zh/users/alex2356" #property version "1.00" //--- Include application class #include "Program.mqh" //+------------------------------------------------------------------+ //| 智能交易系统输入参数 | //+------------------------------------------------------------------+ input int Inp_BaseFont = 10; // 基本字号 input color Caption = C'0,130,225'; // 标题颜色 input color Background = clrWhite; // 背景颜色 input LANG Language = ENGLISH; // 界面语言 input ulong MagicNumber = 1111; // 魔幻数字 //--- CFastTrading program; ulong tick_counter; //+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| 智能系统逆初始化函数 | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { program.OnDeinitEvent(reason); } //+------------------------------------------------------------------+ //| 智能系统即时报价函数 | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| 计时器函数 | //+------------------------------------------------------------------+ void OnTimer(void) { program.OnTimerEvent(); } //+------------------------------------------------------------------+ //| 图表事件函数 | //+------------------------------------------------------------------+ 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: //--- 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;
在公开部分中创建方法:
//--- 标题颜色 void CaptionColor(const color clr); //--- 背景颜色 void BackgroundColor(const color clr); //--- 字号 void FontSize(const int font_size); //--- 字体名 void FontName(const string font_name); //--- 设置界面语言 void SetLanguage(const LANG lang); //--- 设置魔幻数字 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 初始化部分应用它们:
//+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- 初始化类变量 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 初始化中:
//+------------------------------------------------------------------+ //| 智能系统初始化函数 | //+------------------------------------------------------------------+ int OnInit() { //--- tick_counter=GetTickCount(); //--- 初始化类变量 program.FontName("Trebuchet MS"); program.FontSize(Inp_BaseFont); program.BackgroundColor(Background); program.CaptionColor(Caption); program.SetLanguage(Language); program.SetMagicNumber(MagicNumber); //--- 设置交易面板 if(!program.CreateGUI()) { Print(__FUNCTION__," > Failed to create graphical interface!"); return(INIT_FAILED); } //--- return(INIT_SUCCEEDED); }
现在,创建主应用程序窗口。 这可在类的受保护部分里添加 CreateMainWindow() 方法来完成。
protected: //--- forms bool CreateMainWindow(void);
将其实现添加到 MainWindow.mqh 文件中,然后在 CreateGUI() 中调用它。 在此方法实现中,我使用了 CAPTION_NAME 宏替换,这就是为什么应在特殊的 Defines.mqh 文件中创建它的原因。赫兹股票量化软件
//+------------------------------------------------------------------+ //| 创建订单窗体 | //+------------------------------------------------------------------+ bool CFastTrading::CreateMainWindow(void) { //--- 向窗口数组添加窗口指针 CWndContainer::AddWindow(m_main_window); //--- 属性 m_main_window.XSize(400); m_main_window.YSize(182); //--- 坐标 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); //--- 创建窗体 if(!m_main_window.CreateWindow(m_chart_id,m_subwin,CAPTION_NAME,x,y)) return(false); //--- return(true); } //+------------------------------------------------------------------+ //| 创建程序的图形界面 | //+------------------------------------------------------------------+ bool CFastTrading::CreateGUI(void) { //--- 创建著应用程序窗口 if(!CreateMainWindow()) return(false); //--- GUI 创建完成 CWndEvents::CompletedGUI(); return(true); }
现在,创建一个新的宏替换。
//+------------------------------------------------------------------+ //| 宏替换 | //+------------------------------------------------------------------+ #include "Program.mqh" #define CAPTION_NAME (m_language==RUSSIAN ? "Быстрый трейдинг" : "Fast Trading")
编译项目,从而得到主应用程序窗口。 现在,我们添加按钮(图例 1),它将执行所述操作。 为了实现它们,请在类的受保护部分中创建通用的 CreateButton() 方法。赫兹股票量化软件
//--- 按钮 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) { //--- 存储窗口指针 button.MainPointer(window); //--- 创建之前设置属性 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); //--- 创建控制元素 if(!button.CreateButton(text,x_gap,window.CaptionHeight()+y_gap)) return(false); //--- 向数据库添加指向元素的指针 CWndContainer::AddToElementsArray(w_number,button); return(true); } //+------------------------------------------------------------------+ //| 创建订单窗体 | //+------------------------------------------------------------------+ bool CFastTrading::CreateMainWindow(void) { //--- 向窗口数组添加窗口指针 CWndContainer::AddWindow(m_main_window); //--- 属性 m_main_window.XSize(400); m_main_window.YSize(182); //--- 坐标 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); //--- 创建窗体 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 当中。
//+------------------------------------------------------------------+ //| 宏替换 | //+------------------------------------------------------------------+ #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 主应用程序窗口。
如前所述,该应用程序还应有两个窗口来处理市价单和挂单。 因此,创建它们并链接到 “Market Order” 和 “Pending Order” 按钮:相关操作可单击按钮,或按热键 M 和 P 来执行。 因此,在类的受保护部分中添加 CreateMarketOrdersWindow() 和 CreatePendingOrdersWindow() 这两个方法,并在 MainWindow.mqh 中实现它们。赫兹股票量化软件
bool CreateMarketOrdersWindow(void); bool CreatePendingOrdersWindow(void); //+------------------------------------------------------------------+ //| 市价单创建和编辑窗口 | //+------------------------------------------------------------------+ bool CFastTrading::CreateMarketOrdersWindow(void) { //--- 向窗口数组添加窗口指针 CWndContainer::AddWindow(m_orders_windows[0]); //--- 属性 m_orders_windows[0].XSize(450); m_orders_windows[0].YSize(242+58); //--- 坐标 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); //--- 创建窗体 if(!m_orders_windows[0].CreateWindow(m_chart_id,m_subwin,CAPTION_M_ORD_NAME,x,y)) return(false); return(true); } //+------------------------------------------------------------------+ //| 挂单创建和编辑窗口 | //+------------------------------------------------------------------+ bool CFastTrading::CreatePendingOrdersWindow(void) { //--- 向窗口数组添加窗口指针 CWndContainer::AddWindow(m_orders_windows[1]); //--- 属性 m_orders_windows[1].XSize(600); m_orders_windows[1].YSize(580); //--- 坐标 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); //--- 创建窗体 if(!m_orders_windows[1].CreateWindow(m_chart_id,m_subwin,CAPTION_P_ORD_NAME,x,y)) return(false); return(true); }
在这两个窗口中要用到宏替换,因此把它们添加到相应的文件之中:
#define CAPTION_M_ORD_NAME (m_language==RUSSIAN ? "Настройка: Рыночный Ордер" : "Setting: Market Order") #define CAPTION_P_ORD_NAME (m_language==RUSSIAN ? "Настройка: Отложенный Ордер" : "Setting: Pending Order")
现在,在 CreateGUI() 基本方法中调用新创建的窗口,该方法会创建应用程序界面:
//+------------------------------------------------------------------+ //| 创建程序的图形界面 | //+------------------------------------------------------------------+ bool CFastTrading::CreateGUI(void) { //--- 创建主应用程序窗口 if(!CreateMainWindow()) return(false); if(!CreateMarketOrdersWindow()) return(false); if(!CreatePendingOrdersWindow()) return(false); //--- GUI 创建完成 CWndEvents::CompletedGUI(); return(true); }
由于这些已创建窗口是对话框,因此它们将在应用程序启动时显示。 我们需要创建一种机制来显示它们。 单击 "Market order / Pending order" 按钮,或按下热键,即会打开它们。 在基类中找到 OnEvent() 方法主体,并编写所需条件。赫兹股票量化软件
//+------------------------------------------------------------------+ //| 图表事件应答 | //+------------------------------------------------------------------+ void CFastTrading::OnEvent(const int id,const long &lparam,const double &dparam,const string &sparam) { //--- 按下按钮事件 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(); } //--- 按键事件 if(id==CHARTEVENT_KEYDOWN) { //--- 打市价单窗口 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(); } } //--- 开挂单窗口 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 用热键打开和切换窗口。赫兹股票量化软件
如您所见,在打开另一个对话框之前,无需关闭对话框。 它只是简单地切换到另一个窗口 — 这能够节省时间,且在市价单和挂单之间只需一键即可切换。 另一个方便的小技巧是使用 Esc 键关闭对话框的功能。 在测试如何打开窗口时,我要按好几次键来关闭窗口。 因此,我们将代码添加到 “Event” 部分:
//--- 已存在订单窗口 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(); }