第十八節學習一款神經網絡EA

隨著計算能力的增強以及深度學習的出現,人們採用神經網絡技術解決了很多實際問題,同時對神經網絡也越來越重視。那麼,神經網絡如何用於外彙的交易?其實早在2008年就已經出現了神經網絡EA,並在那一年的交易大賽中拿了第一名,所以在十年以前就已經有人把這項技術用來交易了。

鑑於大家對神經網絡沒有一個大致的概念和了解,這裡貼上一個網址供大家學習和參考:

cnblogs.com/subconsciou

這篇文章比較通俗易懂,建議大家細讀,有一定數學基礎的可以去看看神經網絡的教材,認真研究研究。

本節課拿一款神經網絡的EA給大家做一個講解,看看神經網絡類的EA是如何工作的,然後教大家使用MQL4裡面自帶的遺傳算法來尋找優化的參數。

1 策略代碼

這個策略的代碼是2008年那款得第一名的源碼,在網上已經有公佈,有興趣的可以自己搜一下,完整的代碼如下:

 extern double tp1 = 50; extern double sl1 = 50; extern int p1 = 10; extern int x12 = 100; extern int x22 = 100; extern int x32 = 100; extern int x42 = 100; extern double tp2 = 50; extern double sl2 = 50; extern int p2 = 20; extern int x13 = 100; extern int x23 = 100; extern int x33 = 100; extern int x43 = 100; extern double tp3 = 50; extern double sl3 = 50; extern int p3 = 20; extern int x14 = 100; extern int x24 = 100; extern int x34 = 100; extern int x44 = 100; extern int p4 = 20; extern int pass = 1; extern double lots = 0.01; extern int mn = 888; static int prevtime = 0; static double sl = 10; static double tp = 10; //+------------------------------------------------------------------+ //| expert start function | //+------------------------------------------------------------------+ int start() { if (Time[0] == prevtime) { return(0); } prevtime = Time[0]; if (! IsTradeAllowed()) { again(); return(0); } int total = OrdersTotal(); for (int i = 0; i < total; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) { if (OrderSymbol() == Symbol() && OrderMagicNumber() == mn) { return(0); } } } sl = sl1; tp = tp1; int ticket = -1; RefreshRates(); if (Supervisor() > 0) { ticket = OrderSend(Symbol(), OP_BUY, lots, Ask, 1, Bid - sl * Point, Bid + tp * Point, WindowExpertName(), mn, 0, Blue); if (ticket < 0) { again(); } } else { ticket = OrderSend(Symbol(), OP_SELL, lots, Bid, 1, Ask + sl * Point, Ask – tp * Point, WindowExpertName(), mn, 0, Red); if (ticket < 0) { again(); } } //-- Exit -- return(0); } //+--------------------------- getLots ----------------------------------+ double Supervisor() { if (pass == 4) { if (perceptron3() > 0) { if (perceptron2() > 0) { sl = sl3; tp = tp3; return(1); } } else { if (perceptron1() < 0) { sl = sl2; tp = tp2; return(-1); } } return(basicTradingSystem()); } if (pass == 3) { if (perceptron2() > 0) { sl = sl3; tp = tp3; return(1); } else { return(basicTradingSystem()); } } if (pass == 2) { if (perceptron1() < 0) { sl = sl2; tp = tp2; return(-1); } else { return(basicTradingSystem()); } } return(basicTradingSystem()); } double perceptron1() { double w1 = x12 - 100; double w2 = x22 - 100; double w3 = x32 - 100; double w4 = x42 - 100; double a1 = Close[0] - Open[p2]; double a2 = Open[p2] - Open[p2 * 2]; double a3 = Open[p2 * 2] - Open[p2 * 3]; double a4 = Open[p2 * 3] - Open[p2 * 4]; return(w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); } double perceptron2() { double w1 = x13 - 100; double w2 = x23 - 100; double w3 = x33 - 100; double w4 = x43 - 100; double a1 = Close[0] - Open[p3]; double a2 = Open[p3] - Open[p3 * 2]; double a3 = Open[p3 * 2] - Open[p3 * 3]; double a4 = Open[p3 * 3] - Open[p3 * 4]; return(w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); } double perceptron3() { double w1 = x14 - 100; double w2 = x24 - 100; double w3 = x34 - 100; double w4 = x44 - 100; double a1 = Close[0] - Open[p4]; double a2 = Open[p4] - Open[p4 * 2]; double a3 = Open[p4 * 2] - Open[p4 * 3]; double a4 = Open[p4 * 3] - Open[p4 * 4]; return(w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); } double basicTradingSystem() { return(iCCI(Symbol(), 0, p1, PRICE_OPEN, 0)); } void again() { prevtime = Time[1]; Sleep(30000); }

2 主函數原理

首先從START()函數看起,start()函數的第一部分的意思如果當前k線的開盤時間等於之前保存的時間prevtime,那麼就結束,否則的話把該k線的開盤時間賦給prevtime,所以第一部分的內容和我們之前寫的Barjudge()模塊類似,只有在開盤的時候才做交易。

第二部分是意思是,只有允許交易的情況下才做交易,若服務器繁忙或者市場關閉那麼就不做。

第三部分是一個遍歷訂單的操作,相信大家都能看懂,意思是如果當前持有訂單,那麼就不做處理。

第四部分,刷新數據為交易做準備,若判斷交易的函數Supervisor()大於0,則說明是多方走勢,開一個多單,如果Supervisor()小於0,則說明是空方走勢,開一個空單,如果開單不成功,那麼就執行again()函數,把pretime重新賦值回上一根K線的開盤時間,於是下一個tick來的時候程序會重新開單。

這裡註意止損止盈分別為sl1和tp1,要說明一下sl1和tp1是主策略開的單子的止盈止損,sl2、tp2是神經網絡開的空單的止盈止損,sl3、tp3是神經網絡開的多單的止盈止損。

以上就是start函數,很簡單,從這裡面我們知道其實整個策略最核心的其實就是判斷交易的函數Supervisor()。

3 交易判斷函數原理

Supervisor()可以看到有4部分,每一個部分對應了一個通道pass,而pass是一個需要輸入的變量,也就是說根據輸入的參數,EA會運行不同的部分。裡面的perceptron是感知機的意思,關於感知機是什麼,可以看一下之前發的神經網絡介紹的鏈接。

編號5的程序塊的意思是,如果當前pass值設定為4,那麼當3號感知機和2號感知機輸出均大於0時,市場處於多頭方向,supervisor()輸出1,開多單,並採用sl3和tp3作為止損止盈,當3號感知機和1號感知機輸出均小於0時,supervisor()輸出-1,市場處於空頭方向,開空單並採用sl2和tp2作為止損止盈,如果都不滿足則市場處於混沌狀態,這時採用主策略做單,止損止盈保持之前的賦值sl1和tp1不變。

編號6的程序塊的的意思是,當pass值為3時,若感知機2的輸出大於0則返回1,採用sl3和tp3作為止損止盈開多單,否則採用主策略做單,止損止盈保持之前的賦值sl1和tp1不變。

編號7的程序塊的意思是,當pass值為2時,若感知機1的輸出小於0則返回-1,採用sl2和tp2作為止損止盈開空單,否則採用主策略做單,止損止盈保持之前的賦值sl1和tp1不變。

編號8的程序塊,如果pass不等於2、3、4裡面的任意一個數,那麼直接採用主策略做單。

這裡解釋以下為什麼pass有1(其他值)、2、3、4這四個值,當我們剛開始用這款EA的時候,需要把pass設置為1,此時感知器不工作,只有主策略工作,我們可以採用遺傳算法對主策略的參數進行優化;當pass為2時,感知機1和主策略同時工作,此時可以優化感知機1的參數(主策略已經被優化了,對感知機的優化相當於教育感知機如何感受當前的市場);當pass為3時,感知機2和主策略工作,此時可以優化感知機2的參數;最後當pass為4時,感知機1、2 、3和主策略都工作,此時可以優化感知機3的參數,當所有優化做完後,保留pass為4,將參數都調整為最佳參數即可開始交易。

4 主策略函數與感知機函數

主策略函數就是編號9的代碼塊,意思很簡單,返回p1週期的CCI的值,如果該值大於0,配合start()函數那就是做多,反之如果p1週期的CCI的值小於0,那麼就空。

感知機函數有三個,原理上都是一樣的,我們拿感知機1的代碼來看一下它是如何運行的。 1號感知機以P2為間距,從當前K線開始向前挑出了5根K線(包括當前K線),將其前後的開盤價作差(由於是開盤的時候才會激活,而開盤時的close與open相近,所以可以認為是當前K線的開盤價),得出了四個數據,作為感知機的輸入,然後感知機將四個數據乘以對應的參數返回給了Supervisor()函數,如果這個返回值大於0,那麼Supervisor()函數返回1,主函數就會做多。

這裡需要注意的是對於1號感知機,其返回值只有在大於0的時候才會被Supervisor()函數當做有效信號,而在返回值小於0的時候Supervisor()函數會忽視,而對於2號感知機則僅識別小於0的信號。所以實際上,單獨的感知機函數並不是一個完整的感知機,感知機函數和Supervisor()函數聯合起來才是完整的感知機,單一感知機的原理如下圖:

對於1號感知機,它的神經元激活函數為:

對於2號感知機,它的神經元激活函數為:

3號感知機的神經元激活函數為:

當所有參數都優化完畢,即當pass為4時,三個感知機會聯合工作,此時要開多單需要3號感知機與1號感知機返回的參數都大於0,開空單需要3號感知機與2號感知機返回的參數都小於0,也就是說這三個感知機是一個並列的關係,1號與3號是邏輯與的關係,2號和3號也是邏輯與的關係,那麼我們可以畫出當三個感知機一起運作時的原理圖:

其中f4和f5兩個神經元是有程序裡面的與邏輯實現的,f4的激活函數和f1(1號感知機)相同,f5的激活函數和f2相同。

從上圖可以很明顯地看出這是一個雙層的神經網絡系統。

5 策略使用

說了這麼多這款EA的原理,下面說一下如何優化參數(教育感知機)。

首先看一下沒有優化的時候的淨值曲線,採用EURUSD1H級別的數據,點差為當前,直接回測EA得到的結果如下:

可以看到主策略是穩定虧損的策略。

接下來我們對主策略的tp1、sl1、p1三個參數優化,點擊右邊的EA屬性界面,在輸入參數中把tp1、sl1的初始值設置為10,,終止值設置為100,,每次增加值為1,p1的初始值設置為3,終止值設置為100,每次增加1,然後勾選tp1、sl1、p1,將pass值賦值為1,在優化中勾選最大利潤,如圖:

確定後回到測試界面,把優化勾上,然後點擊開始,接下來我們就可以得到不同參數的測試結果的點陣圖:

選取盈利較高的參數,這裡選擇tp1=100,sl1=93,p1=89,然後打開EA屬性,把這三個值輸入到賦值裡面,繼續用當前的點差測試一下,如圖:

可以看到淨值曲線比優化前好很多。

第二步,教育1號感知機,使其參數達到最優,去掉之前tp1、sl1、p1的勾,把x12、x22、x32、x42、tp2、sl2、p2勾上,同樣輸入優化用的初始值、步長和終值,把pass改為2,確定後開始優化,得到以下點陣圖。

選取收益高,較為密集的區域,這裡選擇參數:

x12=14,x22=137,x32=131,x42=67,tp2=96,sl2=62,p2=10

再回測一下,結果如下:

第三、四步的優化步驟同二,在這裡不贅述,得出參數後同樣放到賦值裡面,最後可以得出以下結果:

盈利因子達到了1.33,算得上是盈利的策略,當點差為10時,盈利因子可以達到1.68,10萬美元的賬戶手數為10手的情況下,2個月的最大回撤僅為3.89%,盈利47%,非常可觀。

但是,如作者所說,這個系統存在過度擬合的風險,採用一年的數據測試結果如下:

6 策略評價

可以看到這款EA只在優化時間段表現得不錯,其餘時間段雖然沒有裸策略差,但是還是一個穩定虧損的狀態,所以如作者所說,這款EA只能應用在短期上,若當週出現了虧損,那麼說明市場狀況變了,就要重新對參數進行優化以適應市場的變化。

這款EA若用於實際可能表現不會很好,主要原因還是主策略太差了,樣本外測試也證明了這一點,不過神經網絡這一工具的強大可見一斑。

神經網絡類的EA最需要提防的就是過度擬合,所以尤其需要注意樣本外的測試,一款好的神經網絡策略應該是在訓練樣本內表現和在樣本外表現都比較優異的。


更多內容請關注公眾號【火象】~