量化交易軟件:使用圖形界面處理優(yōu)化結(jié)果
這是處理和分析優(yōu)化結(jié)果想法的續(xù)篇,前一篇文章包含了使用 MQL5 應(yīng)用程序圖形界面來可視化優(yōu)化結(jié)果的方法描述,這一次,任務(wù)會更復(fù)雜一點: 赫茲量化將選擇100個最佳的優(yōu)化結(jié)果并且在圖形界面的表格中顯示它們。
另外,赫茲量化繼續(xù)開發(fā)多交易品種余額圖的想法,它也在另一篇文章中談到了。讓赫茲量化把這兩篇文章的思路綜合起來,使用戶可以在優(yōu)化結(jié)果表格中選擇一行并且在獨立的圖表中得到多交易品種的余額和回撤圖。在優(yōu)化了EA交易的參數(shù)之后,交易者將可以進(jìn)行結(jié)果的快速分析并且選擇合適的工作參數(shù)。

編輯切換為居中
開發(fā)圖形界面
測試 EA 交易的 GUI 將包含下面的原件:
用于控件的表單
用于顯示額外總體信息的狀態(tài)欄
用于把元件分組的頁面:
框架
用于管理在優(yōu)化之后滾動結(jié)果所顯示余額結(jié)果的數(shù)量
在滾動結(jié)果時的延遲毫秒數(shù)
用于開始滾動結(jié)果的按鈕
顯示余額結(jié)果數(shù)量的圖形
全部結(jié)果的圖形
結(jié)果
最佳結(jié)果的表格
余額
用于在表格中選中結(jié)果的多交易品種余額圖形
用于在表格中選中結(jié)果的回撤圖形
數(shù)據(jù)幀重放過程指示
用于創(chuàng)建上面所列出元件的方法的代碼位于獨立的包含文件(include 文件) 中,可以在 MQL 程序類中使用:
//+------------------------------------------------------------------+ //| 用于創(chuàng)建應(yīng)用程序的類 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | //+------------------------------------------------------------------+ class CProgram : public CWndEvents ?{ private: ? //--- 窗口 ? CWindow ? ? ? ? ? m_window1; ? //--- 狀態(tài)條 ? CStatusBar ? ? ? ?m_status_bar; ? //--- 頁面 ? CTabs ? ? ? ? ? ? m_tabs1; ? //--- 文本框 ? CTextEdit ? ? ? ? m_curves_total; ? CTextEdit ? ? ? ? m_sleep_ms; ? //--- 按鈕 ? CButton ? ? ? ? ? m_reply_frames; ? //--- 圖表 ? CGraph ? ? ? ? ? ?m_graph1; ? CGraph ? ? ? ? ? ?m_graph2; ? CGraph ? ? ? ? ? ?m_graph3; ? CGraph ? ? ? ? ? ?m_graph4; ? //--- 表格 ? CTable ? ? ? ? ? ?m_table_param; ? //--- 進(jìn)度條 ? CProgressBar ? ? ?m_progress_bar; ? //--- public: ? //--- 創(chuàng)建圖形界面 ? bool ? ? ? ? ? ? ?CreateGUI(void); ? //--- private: ? //--- 表單 ? bool ? ? ? ? ? ? ?CreateWindow(const string text); ? //--- 狀態(tài)條 ? bool ? ? ? ? ? ? ?CreateStatusBar(const int x_gap,const int y_gap); ? //--- 頁面 ? bool ? ? ? ? ? ? ?CreateTabs1(const int x_gap,const int y_gap); ? //--- 文本框 ? bool ? ? ? ? ? ? ?CreateCurvesTotal(const int x_gap,const int y_gap,const string text); ? bool ? ? ? ? ? ? ?CreateSleep(const int x_gap,const int y_gap,const string text); ? //--- 按鈕 ? bool ? ? ? ? ? ? ?CreateReplyFrames(const int x_gap,const int y_gap,const string text); ? //--- 圖表 ? bool ? ? ? ? ? ? ?CreateGraph1(const int x_gap,const int y_gap); ? bool ? ? ? ? ? ? ?CreateGraph2(const int x_gap,const int y_gap); ? bool ? ? ? ? ? ? ?CreateGraph3(const int x_gap,const int y_gap); ? bool ? ? ? ? ? ? ?CreateGraph4(const int x_gap,const int y_gap); ? //--- 按鈕 ? bool ? ? ? ? ? ? ?CreateUpdateGraph(const int x_gap,const int y_gap,const string text); ? //--- 表格 ? bool ? ? ? ? ? ? ?CreateMainTable(const int x_gap,const int y_gap); ? //--- 進(jìn)度條 ? bool ? ? ? ? ? ? ?CreateProgressBar(const int x_gap,const int y_gap,const string text); ?}; //+------------------------------------------------------------------+ //| 用于創(chuàng)建控件的方法 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?| //+------------------------------------------------------------------+ #include "CreateGUI.mqh" //+------------------------------------------------------------------+
正如上面描述的,表格將顯示100個最佳優(yōu)化結(jié)果 (從最大結(jié)果利潤角度考慮)。因為 GUI 是在優(yōu)化開始之前創(chuàng)建的,表格最開始是空的。列的數(shù)量和抬頭文字是在優(yōu)化數(shù)據(jù)幀處理類中確定的,
讓赫茲量化創(chuàng)建一個含有以下功能的表格:
顯示表頭
排序選項
可以選擇一行
固定選中的行 (沒有去除選擇的功能)
人工調(diào)節(jié)列的寬度
斑馬風(fēng)格的格式
用于創(chuàng)建表格的代碼顯示在下面,為了使表格固定在第二個頁面, 表格對象傳到頁面對象的時候要指定頁面的索引,在這種情況下,表格的 主類是 'Tabs' 元件. 這樣,如果頁面區(qū)域的大小有了改變,表格的大小將也會相對它的主元件而改變,這是在 'Table' 元件的屬性中指定的.
//+------------------------------------------------------------------+ //| 創(chuàng)建主表格 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | //+------------------------------------------------------------------+ bool CProgram::CreateMainTable(const int x_gap,const int y_gap) ?{ //--- 保存主控件的指針 ? m_table_param.MainPointer(m_tabs1); //--- 附加到頁面 ? m_tabs1.AddToElementsArray(1,m_table_param); //--- 屬性 ? m_table_param.TableSize(1,1); ? m_table_param.ShowHeaders(true); ? m_table_param.IsSortMode(true); ? m_table_param.SelectableRow(true); ? m_table_param.IsWithoutDeselect(true); ? m_table_param.ColumnResizeMode(true); ? m_table_param.IsZebraFormatRows(clrWhiteSmoke); ? m_table_param.AutoXResizeMode(true); ? m_table_param.AutoYResizeMode(true); ? m_table_param.AutoXResizeRightOffset(2); ? m_table_param.AutoYResizeBottomOffset(2); //--- 創(chuàng)建控件 ? if(!m_table_param.CreateTable(x_gap,y_gap)) ? ? ?return(false); //--- 把對象加到對象組的統(tǒng)一數(shù)組中 ? CWndContainer::AddToElementsArray(0,m_table_param); ? return(true); ?}
保存優(yōu)化結(jié)果
CFrameGenerator 類是實現(xiàn)用于操作優(yōu)化結(jié)果的,赫茲量化將使用來自文章 在赫茲量化中可視化交易策略的優(yōu)化 中的版本,并且在其中加入所需的方法。除了在幀中保存總余額和最終統(tǒng)計結(jié)果外,赫茲量化還需要單獨保存每個交易品種的余額和回撤。CSymbolBalance 獨立數(shù)組結(jié)構(gòu)將用于保存余額,該結(jié)構(gòu)有兩個目的,數(shù)據(jù)被保存到它的數(shù)組中,然后會在一個通用數(shù)組中傳給一個數(shù)據(jù)幀,在優(yōu)化之后,數(shù)據(jù)將會從數(shù)據(jù)幀數(shù)組中展開再傳回給這個結(jié)構(gòu)的數(shù)組中,被顯示在多交易品種圖形中。
//--- 用于所有交易品種余額的數(shù)組 struct CSymbolBalance ?{ ? double ? ? ? ? ? ?m_data[]; ?}; //+------------------------------------------------------------------+ //| 用于操作優(yōu)化結(jié)果的類 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? | //+------------------------------------------------------------------+ class CFrameGenerator ?{ private: ? //--- 余額結(jié)構(gòu) ? CSymbolBalance ? ?m_symbols_balance[]; ?};
交易品種的枚舉使用‘;’來分隔,將會作為字符串型參數(shù)傳給數(shù)據(jù)幀。最開始,數(shù)據(jù)是以字符串?dāng)?shù)組的形式全部保存到數(shù)據(jù)楨的,但是字符串?dāng)?shù)組是不能傳給數(shù)據(jù)幀的,嘗試給 FrameAdd() 函數(shù)傳一個字符串?dāng)?shù)組,將會在編譯的時候產(chǎn)生錯誤:
字符串?dāng)?shù)組和包含對象的結(jié)構(gòu)不被允許
另一個選項是把報告寫到一個文件中,再把文件傳給數(shù)據(jù)幀。然而,這個選項是不合適的: 赫茲量化將必須把結(jié)果特別頻繁地記錄到硬盤中。
所以,我決定把所有所需數(shù)據(jù)收集到一個數(shù)組中,然后根據(jù)幀參數(shù)中包含的鍵值來展開數(shù)據(jù)。統(tǒng)計變量將包含在數(shù)組的最開始,隨后是總的余額,以及每個交易品種分別的獨立余額,最后是兩個軸上分別的回撤數(shù)據(jù)。
下面的結(jié)構(gòu)圖顯示了數(shù)組中封裝數(shù)據(jù)的順序,只使用了兩個交易品種,這樣是為了使結(jié)構(gòu)足夠短。

編輯
圖 1. 數(shù)組中數(shù)據(jù)分布的順序.
所以,我們需要鍵值來確定數(shù)組中每個范圍的索引,統(tǒng)計變量的數(shù)量是常數(shù),會進(jìn)一步判斷。赫茲量化將在表格中顯示5個變量和通過數(shù),確保這個結(jié)果的數(shù)組可以在優(yōu)化之后訪問到:
//--- 統(tǒng)計參數(shù)的數(shù)量 #define STAT_TOTAL 6
通過數(shù)
測試結(jié)果
利潤 (STAT_PROFIT)
交易數(shù)量 (STAT_TRADES)
回撤 (STAT_EQUITY_DDREL_PERCENT)
采收率 (STAT_RECOVERY_FACTOR)
余額數(shù)據(jù)的大小對總數(shù)據(jù)和單獨的交易品種數(shù)據(jù)是相同的,這個值將以一個double 類型參數(shù)傳給 FrameAdd()函數(shù)。為了確定測試中使用的交易品種,我們將在每個通過中定義它們,具體是根據(jù)交易歷史在 OnTester() 函數(shù)中實現(xiàn)的。這個信息將會以字符串型參數(shù)傳給 FrameAdd() 函數(shù)。