當前位置:
首頁 > 最新 > 在 METATRADER 中使用神經網路

在 METATRADER 中使用神經網路

簡介

你們中很多人可能已考慮過在你們的 EA 中使用神經網路的可能性。 這個主題非常熱門,尤其是在 2007 年自動交易錦標賽上,Better 以其基於神經網路的系統橫掃對手之後,更是炙手可熱。 很多互聯網論壇充斥著與神經網路和外匯交易相關的主題。 然而遺憾的是,編寫神經網路的本機 MQL4 實現並不簡單。 它要求一些編程技巧,而且結果並不會很有效,尤其是當你想要在測試程序中針對大量數據測試你的最終結果時。

本文中,我將展示如何在你的 MQL4 代碼中使用免費(在 LGPL 下)的著名快速人工神經網路庫 (FANN),同時避免某些障礙和限制。 我進一步假設讀者熟悉人工神經網路 (ann) 和與此主題相關的術語,因此我會側重介紹使用以 MQL4 語言編寫的人工神經網路的具體實現的實踐性環節。


為了充分了解 FANN 實現的可能性,讀者需要熟悉其文檔和最常用的函數。 FANN 的典型用例是創建一個簡單的前饋網路,用一些數據訓練此網路並運行它。 然後可將已創建並訓練過的網路保存到文件中,之後可恢復以備進一步使用。 要創建一個人工神經網路,用戶必須使用 fann_create_standard() 函數。 我們來看看它的語法:

FANN_EXTERNALstructfann *FANN_API fann_create_standard(unsignedintnum_layers,intlNnum, ... )

其中,num_layers代表總層數,包括輸入和輸出層。 lNnum 和以下參數代表各個層(從輸入層開始,以輸出層結束)中的神經元數量。 要創建一個包含一個隱藏層且層中有 5 個神經元、10 個輸入和 1 個輸出的網路,用戶必須進行如下調用:

fann_create_standard(3,10,5,1);

一旦創建了人工神經網路,下一步操作就是使用一些輸入和輸出數據對其進行訓練。 最簡單的訓練方法是增量訓練,可通過以下函數執行:

FANN_EXTERNALvoidFANN_API fann_train(structfann * ann, fann_type *input, fann_type * desired_output )

此函數將指針指向之前由 fann_create_standard() 返回的struct fann以及輸入數據向量和輸出數據向量。 輸入和輸出向量是fann_type類型的數組。 該類型事實上是doublefloat類型,具體取決於 FANN 的編譯方式。 在此實現中,輸入和輸出向量都將成為double數組。

一旦人工神經網路訓練完成,下一個期望功能將是運行該網路。 函數實現定義如下:

FANN_EXTERNAL fann_type * FANN_API fann_run(structfann * ann, fann_type *input)

此函數將指針指向struct fann,代表之前創建的網路和已定義類型(double數組)的輸入向量。 返回的值是一個輸出向量數組。 這個事實是非常重要的,對於一個輸出網路,我們始終獲得一個帶輸出值的元素數組,而不是輸出值本身。

遺憾的是,大部分 FANN 函數使用指向struct fann的指針, 代表無法直接由不支持結構作為數據類型的 MQL4 處理的人工神經網路 為了避免該限制,我們必須用某個方法進行一些包裝,繞開 MQL4。 最簡單的方法是創建一個用於保存正確值的struct fann指針數組,並用int變數表示的索引來參考它們。用這種方法,我們可以將不受支持的變數類型替換為受支持類型,並創建一個可以輕鬆與 MQL4 代碼整合的包裝庫。


據我所知,MQL4 不支持帶變數參數列表的函數,所以我們還得解決這個問題。 另一方面,如果調用了帶過多參數的 C 函數(變數參數長度)且並未發生任何問題,那麼我們可以假定 MQL4 函數中有固定的最大參數數量被傳遞到 C 庫。 結果包裝函數如下所示:

/* Creates a standard fully connected backpropagation neural network.* num_layers - The total number of layers including the input and the output layer.* l1num - number of neurons in 1st layer (inputs)* l2num, l3num, l4num - number of neurons in hidden and output layers (depending on num_layers).* Returns:* handler to ann, -1 on error*/int__stdcall f2M_create_standard(unsignedintnum_layers,intl1num,intl2num,intl3num,intl4num);

我們將先導的fann_更改為f2M_(表示 FANN TO MQL),使用靜態的參數數量(4 層),返回值現在是人工神經網路的內部數組的索引,其中包含 FANN 操作所需的struct fann數據。 用這種方法,我們可以輕鬆從 MQL 代碼中調用此類函數。

同樣的方式適用於以下情況:

/* Train one iteration with a set of inputs, and a set of desired outputs.* This training is always incremental training, since only one pattern is presented.* ann - network handler returned by f2M_create_** *input_vector - array of inputs* *output_vector - array of outputs* Returns:* 0 on success and -1 on error*/int__stdcall f2M_train(intann,double*input_vector,double*output_vector);

/* Run fann network* ann - network handler returned by f2M_create_** *input_vector - array of inputs* Returns:* 0 on success, negative value on error* Note:* To obtain network output use f2M_get_output().* Any existing output is overwritten*/int__stdcall f2M_run(intann,double*input_vector);

最後一點也非常重要,即你應該通過以下調用清除你曾創建的人工神經網路:

/* Destroy fann network* ann - network handler returned by f2M_** Returns:* 0 on success -1 on error* WARNING: the ann handlers cannot be reused if ann!=(_ann-1)* Other handlers are reusable only after the last ann is destroyed.*/int__stdcall f2M_destroy(intann);

要釋放人工神經網路句柄,你應該以與網路創建順序相反的順序清除網路。 或者可以使用以下方式:

/* Destroy all fann networks* Returns:* 0 on success -1 on error*/int__stdcall f2M_destroy_all_anns();

但我很肯定,你們有些人可能更願意保存已訓練過的網路以留待後用,如下所示:

/* Save the entire network to a configuration file.* ann - network handler returned by f2M_create** Returns:* 0 on success and -1 on failure*/int__stdcall f2M_save(intann,char*path);

當然,以後可以通過以下代碼載入(更確切地說是重新創建)保存的網路:

/* Load fann ann from file* path - path to .net file* Returns:* handler to ann, -1 on error*/int__stdcall f2M_create_from_file(char*path);

一旦我們了解了基本函數,我們就可以在我們的 EA 中試著使用它們,但首先我們需要安裝 Fann2MQL 包。


為了便於使用此包,我創建了 msi 安裝程序,內含所有源代碼和預編譯庫以及聲明所有函數的Fann2MQL.mqh 頭文件。

安裝程序相當簡單。 首先你會被告知,Fann2MQL 擁有 GPL 許可:

Fann2MQL 安裝步驟 1

然後選擇要安裝此包的文件夾。 可以使用默認的Program FilesFann2MQL或直接安裝到你的Meta Traderexperts目錄。 後者將把所有文件直接放到它們的位置,否則你必須手動複製它們。

Fann2MQL 安裝步驟 2

安裝程序將文件放到以下文件夾:

include folder

libraries folder

src folder

如果選擇安裝到 Fann2MQL 專用文件夾,請將其includelibraries子文件夾的內容複製到你 Meta Trader 的相應目錄下。

安裝程序還會將 FANN 庫安裝到你的系統庫文件夾內(大部分情況下是 Windowssystem32)。 src文件夾包含 Fann2MQL 的所有源代碼。 如果需要了解內部構件的更多信息,可以閱讀源代碼,它是根本性的文檔。 如果願意的話,也可改進這些代碼並添加其他功能。 如果你實現了什麼有趣的東西,我鼓勵你把你的包發給我。

一旦安裝了 Fann2MQL,你就可以開始編寫你自己的 EA 或指標。 神經網路有大量可能的應用。 你可用它們預測未來的價格變動,但此類預測的質量以及真正充分利用其優勢的可能性令人存疑。 你可試著用強化學習(也稱 Q 學習或類似說法)技巧編寫你自己的策略。 你可試著將神經網路用作你探試性 EA 的信號過濾器,或將所有這些技巧組合起來,再加上你真正想要的東西。 想像力是你唯一的束縛。

這裡我將介紹一個例子,即將神經網路用作一個簡單過濾器,以過濾 MACD 生成的信號。 請勿將其視為有價值的 EA,而應視為 Fann2MQL 的一個示例應用。 在說明示例 EA: NeuroMACD.mq4 的工作方式時,我會展示如何在 MQL 中有效利用 Fann2MQL。

每個 EA 的第一件事都是聲明全局變數,定義和包括部分。 以下是包含這些內容的 NeuroMACD 的開頭部分:

// Include Neural Network package#include// Global defines#defineANN_PATH"C:\ANN"// EA Name#defineNAME"NeuroMACD"//---- input parametersexterndoubleLots=0.1;externdoubleStopLoss=180.0;externdoubleTakeProfit=270.0;externintFastMA=18;externintSlowMA=36;externintSignalMA=21;externdoubleDelta=-0.6;externintAnnsNumber=16;externintAnnInputs=30;externboolNeuroFilter=true;externboolSaveAnn=false;externintDebugLevel=2;externdoubleMinimalBalance=100;externboolParallel=true;// Global variables// Path to anns folderstringAnnPath;// Trade magic numberintMagicNumber=65536;// AnnsArray[ann#] - Array of annsintAnnsArray[];// All anns loded properly statusboolAnnsLoaded=true;// AnnOutputs[ann#] - Array of ann returned returneddoubleAnnOutputs[];// InputVector[] - Array of ann input datadoubleInputVector[];// Long position ticketintLongTicket=-1;// Short position ticketintShortTicket=-1;// Remembered long and short network inputsdoubleLongInput[];doubleShortInput[];

包括命令可載入 Fann2MQL.mqh 頭文件,此文件中包含所有 Fann2MQL 函數的聲明。 之後,所有 Fann2MQL 包函數都可在腳本中使用。 ANN_PATH常數定義使用已訓練的 FANN 網路存儲和載入文件的路徑。你需要創建該文件夾,即 C:ANN。 NAME常數包含此 EA 的名稱,它將在稍後用於載入和保存網路文件。 輸入參數很是明顯,那些不那麼明顯的會在後文中說明,全局變數也同樣如此。

每個 EA 的切入點是其 init() 函數:

intinit() {inti,ann;if(!is_ok_period(PERIOD_M5)) { debug(,"Wrong period!");return(-1); } AnnInputs=(AnnInputs/3)*3;// Make it integer divisible by 3if(AnnInputs

首先,它檢查 EA 是否應用於正確的時間範圍。AnnInputs變數包含神經網路輸入數。 由於我們將使用 3 組不同的參數,所以我們希望它能被 3 除盡。計算 AnnPath以反映 EANAMEMagicNumber,它是根據SlowMAFastMASignalMA輸入參數(這些參數稍後將用於 MACD 指標信號)計算得出的。 一旦它知道了 AnnPath,EA 會嘗試使用ann_load()函數(下文會介紹此函數)載入神經網路。 已載入網路中,一半用於執行多頭倉過濾,另一半執行空頭倉過濾。AnnsLoaded變數用於表明所有網路都執行了正確的初始化。 你可能已經注意到,此示例 EA 正在嘗試載入多個網路。 我不確定此行為在此應用中是否必要,但我想向你展示 Fann2MQL 的全部潛力,它同時可處理多個網路,並可利用多個核心和 CPU 實現並行處理。 為此,Fann2MQL 利用了 Intel? 線程構建模塊 技術。 函數f2M_parallel_init()用於初始化該介面。

以下是我初始化網路的方式:

intann_load(stringpath) {intann=-1;/* Load the ANN */ann=f2M_create_from_file(path);if(ann!=-1) { debug(1,"ANN: ""+path+"" loaded successfully with handler "+ann); }if(ann==-1) {/* Create ANN */ann= f2M_create_standard(4,AnnInputs,AnnInputs,AnnInputs/2+1,1); f2M_set_act_function_hidden(ann,FANN_SIGMOID_SYMMETRIC_STEPWISE); f2M_set_act_function_output(ann,FANN_SIGMOID_SYMMETRIC_STEPWISE); f2M_randomize_weights(ann,-0.4,0.4); debug(1,"ANN: ""+path+"" created successfully with handler "+ann); }if(ann==-1) { debug(,"INITIALIZING NETWORK!"); }return(ann); }

如你所見,如果f2M_create_from_file()失敗(即返回值為負值),則使用f2M_create_standard()函數創建網路,並用參數指示所創建的網路應有 4 個層(包括輸入和輸出層)、AnnInput 輸入、第一個隱藏層中的 AnnInput 神經元、第二個隱藏層中的 AnnInput/2+1 神經元和輸出層中的 1 個神經元。f2M_set_act_function_hidden()用於將隱藏層的激活函數設置為 SIGMOID_SYMMETRIC_STEPWISE(請參考 fann_activationfunc_enum 的 FANN 文檔),並對輸出層執行同樣的操作。 然後調用f2m_randomize_weights(),用於初始化網路中的神經元連接權值。 這裡我用了 的範圍,但你可根據具體應用使用任何其他範圍。

這時你可能已經發現我用了好幾次debug()函數。 要改變你 EA 的詳細級別,這是最簡單的方法之一。 你可將此函數與輸入參數DebugLevel配合使用,調整你代碼生成調試輸出的方式。

voiddebug(intlevel,stringtext) {if(DebugLevel>=level) {if(level==) text="ERROR: "+text;Print(text); } }

如果debug()函數的第一個參數調試level高於DebugLevel,則此函數不生成任何輸出。 如果是低於或等於,則將列印出text字元串。 如果調試級別為 0,則會在開頭添加字元串「ERROR: 」。 這樣你就可以將你代碼生成的調試劃分為多個級別。 最重要的是可能發生的錯誤,因此它們被分配到級別 0。 它們會被列印出來,除非你將你的DebugLevel降至 0 以下(不建議這麼做)。 1 級時會列印一些重要信息,例如網路成功載入或創建的確認信息。 2 級或以上時,列印內容的重要性會逐漸降低。

在詳細說明start()函數之前(篇幅會較長),我需要介紹另外一些函數,用於準備網路輸入和運行實際網路:

voidann_prepare_input() {inti;for(i=;i

函數ann_prepare_input()用於準備網路的輸入名稱(故此而得名)。 其用途很簡單,但有一點必須注意,即輸入數據必須進行正確的標準化。 這種情況下的標準化並不複雜,我只用了 MACD 主要值和信號值,這些值絕不會超出相關數據的所需範圍。 在真實案例中,你也許應該更加關注這個問題。 你可能已經猜到過,選擇網路輸入的正確輸入參數、進行編碼、分解以及標準化正是神經網路處理的最重要因素之一。

正如前面所說,Fann2MQL 能夠擴展 MetaTrader 的正常功能,即神經網路的並行多線程處理。 全局參數Parallel控制此行為。 run_anns()函數運行所有已初始化的網路,並獲取它們的輸出,然後存儲到 AnnOutput[] 數組中。AnnOutput[]數組。anns_run_parallel函數負責以多線程方式處理任務。 它調用f2m_run_parallel(),此函數將待處理網路數量視為第一個參數,第二個參數是一個包含要運行的所有網路的句柄的數組, 並提供輸入向量作為第三個參數。 所有網路必須針對相同的輸入數據運行。 通過多次調用f2m_get_output() 從網路中獲取輸出。

現在讓我們看一看start()函數:

intstart() {inti;boolBuySignal=false;boolSellSignal=false;doubletrain_output[1];/* Is trade allowed? */if(!trade_allowed()) {return(-1); }/* Prepare and run neural networks */ann_prepare_input(); run_anns();/* Calulate last and previous MACD values.* Lag one bar as current bar is building up*/doubleMacdLast=iMACD(NULL,,FastMA,SlowMA,SignalMA,PRICE_CLOSE,MODE_MAIN,1);doubleMacdPrev=iMACD(NULL,,FastMA,SlowMA,SignalMA,PRICE_CLOSE,MODE_MAIN,2);doubleSignalLast=iMACD(NULL,,FastMA,SlowMA,SignalMA,PRICE_CLOSE,MODE_SIGNAL,1);doubleSignalPrev=iMACD(NULL,,FastMA,SlowMA,SignalMA,PRICE_CLOSE,MODE_SIGNAL,2);/* BUY signal */if(MacdLast>SignalLast && MacdPrevSignalPrev) { SellSignal=true; }/* No Long position */if(LongTicket==-1) {/* BUY signal */if(BuySignal) {/* If NeuroFilter is set use ann wise to decide :) */if(!NeuroFilter || ann_wise_long()>Delta) { LongTicket=OrderSend(Symbol(),OP_BUY,Lots,Ask,3,Bid-StopLoss*Point,Ask+TakeProfit*Point, NAME+"-"+"L ",MagicNumber,,Blue); }/* Remember network input */for(i=;i) {OrderClose(LongTicket,Lots,Bid,3); } }if(OrderCloseTime()!=) {// Order is closedLongTicket=-1;if(OrderProfit()>=) { train_output[]=1; }else{ train_output[]=-1; }for(i=;iDelta) { ShortTicket=OrderSend(Symbol(),OP_SELL,Lots,Bid,3,Ask+StopLoss*Point,Bid-TakeProfit*Point,NAME+"-"+"S ", MagicNumber,,Red); }/* Remember network input */for(i=;i) {OrderClose(LongTicket,Lots,Bid,3); } }if(OrderCloseTime()!=) {// Order is closedShortTicket=-1;if(OrderProfit()>=) { train_output[]=1; }else{ train_output[]=-1; }for(i=1;i

我只簡單的介紹一下,因為注釋里已經有很詳盡的說明了。 run_anns()()檢查是否允許交易。 基本上,它檢查 AnnsLoaded變數指示所有人工神經網路都正確進行了初始化,然後檢查正確的時間範圍周期最小帳戶餘額,最後允許僅在新條柱上第一次價格變動時進行交易。 接下來的兩個函數用於準備網路輸入和執行網路處理,上面幾行中已有說明。 下一步,我們計算和放入變數,以對最後一個形成的條柱及其前一個條柱的信號和主線的 MACD 值進行後續處理。 忽略當前條柱,因為它尚未形成,可能會重新繪製。 run_anns()MACD 信號主線交叉信號來計算SellSignal 和 BuySignal。 這兩個信號用於對稱的多頭倉和空頭倉處理,因此我將僅說明多頭倉的情況。

run_anns()變數包含當前已建倉位的編號數。 如果它等於 -1,則不建倉,因此如果設置了主線交叉信號,可能就表示有建多頭倉的好機會。 如果變數NeuroFilter未設置,則建立多頭倉,並且這種情況下神經網路不對信號進行過濾 -- 發送的訂單是買入訂單。 此時,LongInput變數會記住ann_prepare_input()準備的InputVector,以備後用。

如果LongTicekt變數包含有效編號數,EA 會檢查訂單是仍處於未結狀態還是已被 StopLoss 或 TakeProfit 平倉。 如果訂單仍未結,什麼都不會發生,但如果已平倉,則將計算僅有一個輸出的train_output[]向量,如果是虧損平倉,輸出值為 -1,如果是獲利平倉,輸出值為 1。 然後將該值傳遞給ann_train()函數,所有負責處理多頭倉的網路都將用它進行訓練。 變數LongInput用作輸入向量,它包含ann_prepare_input()InputVector。 通知這種方式告知網路哪個信號可實現獲利,哪個信號不行。

一旦你將已訓練的網路從NeuroFilter切換到true,則啟用網路過濾。 run_anns()ann_wise_long(),所得值為所有用於處理多頭倉的網路返回的值的平均值。 run_anns()參數作為一個閾值,指示過濾信號是否有效。像很多其他值一樣,此閾值也是通過優化流程獲取的。

現在,一旦我們了解了它的工作原理,我會向你展示它的應用。 測試貨幣對當然是 EURUSD。 我用的是來自 Alpari 的數據,轉換至 M5 時間範圍。 用於訓練/優化的周期為 2007.12.31 至 2009.01.01,用於測試目的的周期為 2009.01.01 至 2009.03.22。 第一次運行時,我嘗試獲取 StopLoss、TakeProfit、SlowMA、FastMA 和 SignalMA 參數的最具盈利能力的值,然後用代碼編寫到 NeuroMACD.mq4 文件中。 NeuroFIlterSaveAnn都被禁用,AnnsNumber則設置為 0 以避開神經網路處理。 我使用了遺傳演算法進行優化。 獲取值後,所獲報告如下:

基本參數優化後的訓練數據報告。

正如你所見,我在迷你帳戶上運行了這個 EA,使用的是 0.01 手數和 200 的初始餘額。 當然你也可以根據自己的帳戶設置或偏好調整這些參數。

此時我們已有足夠的獲利和虧損交易數,所以我們可以啟用 SaveAnn,都被並將AnnsNumber設為 30。= 30。 做完這些,我再次運行了測試程序。 結果除了一點以外,其他完全相同,這一點不同之處就是流程慢了不少(使用了神經網路處理的緣故),並且文件夾 C:ANN 中滿是已訓練的網路,如下圖中所示。 運行此流程之前,確保 C:ANN 文件夾是存在的!

C:\ANN\ 文件夾。

訓練了網路之後,就到了測試其表現的時候了。 首先我們將用訓練數據來做一下測試。 將NeuroFilter切換到true,並將SaveAnn更改為false,然後啟動測試程序。 所得結果顯示在下方。 注意,你的測試結果可能會有少許不同,因為網路初始化過程中提供的神經元連接權值有一點隨機性(此例中我明確調用了ann_load()內的2M_randomize_weights()) 。

啟用信號神經過濾時在訓練數據上所獲的結果。

凈利潤略有增長 (20.03 vs 16.92),但獲利因子高了很多 (1.25 vs 1.1)。 交易數少了很多 (83 vs 1188),平均連續虧損數從 7 降至 2。 但這僅僅表明神經信號過濾正在發揮作用,卻隻字未提它對訓練期間未使用的數據做了什麼。 以下是從測試周期 (2009.01.01 - 2009.30.28) 中獲取的結果:

啟用神經過濾後從測試數據中獲得的結果。

執行的交易數相當少,很難說這個策略的質量到底如何,但我並不是要教你如何編寫最具盈利能力的 EA,而是說明如何在你的 MQL4 代碼中使用神經網路。 這種情況下,要看到使用神經網路的實際效果,只有將啟用和禁用NeuroFilter時 EA 在測試數據上所得的結果進行比較。 以下是未採用神經信號過濾時從測試數據周期中獲得的結果:

無神經過濾時測試數據所得結果

差異相當明顯。 可以看到,神經信號過濾將虧損 EA 轉變成了獲利 EA!


我希望你從本文中學會了如何在 MetaTrader 中使用神經網路。 藉助簡單的免費開源包 Fann2MQL,你可把神經網路層添加到幾乎任何 Expert Advisor 中,或開始嘗試編寫自己的完全或部分基於神經網路的 Expert Advisor。 獨有的多線程功能可以大大加快你的處理速度(尤其是在優化某些參數時),具體取決於你的 CPU 內核數量。 在一個案例中,它縮短了我的強化學習的優化時間,以 4 核 Intel CPU 為基礎,將 EA 處理時間從 4 天左右縮短至「僅」28 小時。

請注意,本文僅介紹 Fann2MQL 的一些非常基本的用法。 因為此軟體包並不比 FANN 複雜多少,你可使用所有用於管理 FANN 網路的工具,例如:

Fanntool: http://code.google.com/p/fanntool/

FannExplorer: http://leenissen.dk/fann/index.php?p=gui.php

Fann Matlab bindings: http://www.sumowiki.intec.ugent.be/index.php/FANN_Bindings

快速人工神經網路庫的主頁上還有更多有關 FANN 的工具: http://leenissen.dk/fann/!


寫下這篇文章後,我找到了 NeuroMACD.mq4 的一個小錯誤。 用於空頭倉的 OrderClose() 函數使用的是多頭倉編號。 這導致策略發生傾斜,更可能在空頭時保留倉位,而在多頭時平倉:

/* Maintain short position */OrderSelect(ShortTicket,SELECT_BY_TICKET);if(OrderCloseTime()==) {// Order is openedif(BuySignal &&OrderProfit()>) {OrderClose(LongTicket,Lots,Bid,3); } }

在此腳本的正確版本中,我已經修復了這個問題,並完全移除了 OrderClose() 策略。 這不會改變神經過濾對 EA 的整體影響,但餘額曲線形狀會大有不同。 本文隨附了此 EA 的這兩個版本。


喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 EA那些事 的精彩文章:

MT4自帶EA:MACD Sample詳解與實戰分析

TAG:EA那些事 |