我相信,所有开始了解神经网络的交易人员都会认同,在市场分析中使用它们该会有多棒!现在市面上有很多程序,允许您方便地创建具有任意配置的您自己的神经网络,并在可视化模式下对它们进行训练和测试。您可以从客户端将必要的信息导出至神经网络程序并进行分析。
但如果您希望在自动交易中使用创建的神经网络将会怎么样?有没有可能使“EA 交易”连接神经网络并在实时模式下进行交易?
完全可行!有多个神经网络程序具有所需的程序接口。其中之一就是 NeuroSolutions。它最新的版本是第 6 版,但该版本尚未普及,所以现在最流行的版本是第 5 版。这也是本文介绍与第 5 版交互的原因。您需要该程序的完整版本;它包含我们需要的自定义“解决方案向导”。
我们测试示例的策略将十分简单。我们称其为 WeekPattern。当柱在 D1 时间表开盘时,它将使用一个神经网络预测柱的收盘价。基于获得的信息,它将进行买入或卖出交易并保持一整天。价格预测将基于前 5 个柱的 OHLC 值(开盘价、最高价、最低价、收盘价)。为提高神经网络操作的准确性,我们将仅向其发送相对于当前(零)柱的开盘价的价格变化,而不是价格本身。
在我们开始创建神经网络之前,我们先编写一个 MQL5 脚本,它将以所需格式从客户端导出所有报价。这些信息是训练神经网络所需要的。数据将导出为文本文件。以逗号分隔的字段名称将列示在文件的第一个列表中。余下的行将用于逗号分隔的数据。每一行都是神经网络输入和输出的组合。在我们的案例中,脚本将在每一行后移价格历史数据的一个柱,并在行中写入 6 个柱(过去的 5 个柱为输入,当前柱为输出)的 OHLC 值。
脚本 скрипт WeekPattern-Export.mq5 应在要求的交易品种的规定时间表上启动(在我们的的示例中为 D1 EURUSD)。您应在设置中指定文件名和所需的行数(D1 的 260 行系约 1 年的历史记录)。脚本的完整代码如下:
#property script_show_inputs //+------------------------------------------------------------------+ input string Export_FileName = "NeuroSolutions\\data.csv"; // File for exporting (in the folder "MQL5\Files") input int Export_Bars = 260; // Number of lines to be exported //+------------------------------------------------------------------+ void OnStart() { // Create the file int file = FileOpen(Export_FileName, FILE_WRITE|FILE_CSV|FILE_ANSI, ','); if (file != INVALID_HANDLE) { // Write the heading of data string row=""; for (int i=0; i<=5; i++) { if (StringLen(row)) row += ","; row += "Open"+i+",High"+i+",Low"+i+",Close"+i; } FileWrite(file, row); // Copy all required information from the history MqlRates rates[], rate; int count = Export_Bars + 5; if (CopyRates(Symbol(), Period(), 1, count, rates) < count) { Print("Error! Not enough history for exporting of data."); return; } ArraySetAsSeries(rates, true); // Write data for (int bar=0; bar<Export_Bars; bar++) { row=""; double zlevel=0; for (int i=0; i<=5; i++) { if (StringLen(row)) row += ","; rate = rates[bar+i]; if (i==0) zlevel = rate.open; // level for counting of prices row += NormalizeDouble(rate.open -zlevel, Digits()) + "," + NormalizeDouble(rate.high -zlevel, Digits()) + "," + NormalizeDouble(rate.low -zlevel, Digits()) + "," + NormalizeDouble(rate.close-zlevel, Digits()); } FileWrite(file, row); } FileClose(file); Print("Export of data finished successfully."); } else Print("Error! Failed to create the file for data export. ", GetLastError()); } //+------------------------------------------------------------------+
导出数据后,我们获得 data.csv 文件;文件的前几行(用作示例)如下所示:
Open0,High0,Low0,Close0,Open1,High1,Low1,Close1,Open2,High2,Low2,Close2,Open3,High3,Low3,Close3,Open4,High4,Low4,Close4,Open5,High5,Low5,Close5 0,0.00463,-0.0041,0.00274,-0.00518,0.00182,-0.00721,-6e-005,0.00561,0.00749,-0.00413,-0.00402,0.02038,0.02242,0.00377,0.00565,0.03642,0.0379,0.01798,0.02028,0.0405,0.04873,0.03462,0.03647 0,0.007,-0.00203,0.00512,0.01079,0.01267,0.00105,0.00116,0.02556,0.0276,0.00895,0.01083,0.0416,0.04308,0.02316,0.02546,0.04568,0.05391,0.0398,0.04165,0.04504,0.05006,0.03562,0.0456 0,0.00188,-0.00974,-0.00963,0.01477,0.01681,-0.00184,4e-005,0.03081,0.03229,0.01237,0.01467,0.03489,0.04312,0.02901,0.03086,0.03425,0.03927,0.02483,0.03481,0.02883,0.04205,0.02845,0.03809
这是 NeuroSolutions 可以理解的格式。现在,我们可以开始创建和训练神经网络了!
使用 NeuroSolutions,您可以快速创建神经网络,即便您是第一次接触该软件、对神经网络一无所知。为此,在程序开始时选择初学者向导 NeuralExpert (Beginner)(NeuralExpert (初学者)):
您应在其中指定需要神经网络解决的问题类型:
然后指定我们在上一章创建的包含训练信息的文件:
选择文件中除零柱字段以外的所有字段作为神经网络的输入:
由于我们没有文本字段,不要选择任何项:
再次指定包含训练信息的文件:
仅为神经网络选择一个输出:
向导默认创建最简单的神经网络。我们就接受默认设置,无需更改:
向导完成了神经网络的创建(还不是受训的神经网络,仅仅是个简单架构):
现在,我们可以使用它了!我们可以对它进行训练、测试,并将它用于数据分析。
如果您单击 Test(测试)按钮,您将看到未受训的神经网络是如何解决我们的问题的。回答测试向导的问题:
基于来自同一文件的信息执行测试:
测试结束。在窗口 "Output vs. Desired Plot"(输出 vs. 期望绘图)中,您可以看到图表上显示了从我们的历史数据神经网络获得的值(红色)和实际值(蓝色)。可以看到它们之间存在较大差异:
我们现在来对神经网络进行训练。为此,单击菜单下方工具栏上的绿色 Start(开始)按钮。训练将在数秒钟后结束,同时图表将发生变化:
在图表中,您现在可以看到神经网络显示的结果相比实际值已极为接近。因此,您可以用它来进行交易。将此神经网络保存在名称 WeekPattern 下。
无需退出 NeuroSolutions,单击 CSW 按钮以启动 Custom Solution Wizard(自定义解决方案向导)。我们需要从当前神经网络生成一个 DLL。
该向导可生成不同程序的 DLL。据我所知,要编译 DLL 您需要下列版本之一的 Visual C++:5.0/6.0/7.0 (.NET 2002)/7.1 (.NET 2003)/8.0 (.NET 2005)。出于某些原因,我们无法使用 Express 版本(我已确认)。
目标应用程序的列表中没有 MetaTrader。这就是我们选择 Visual C++ 的原因。
保存结果的路径:
如果一切顺利,向导显示:
向导指定的文件夹中将出现很多文件。我们最常用的是:WeekPattern.dll,它包含我们的神经网络以及与其交互的程序界面;而文件 WeekPattern.nsw 包含训练后神经网络的平衡设置。在其他文件中,您可以找到包含使用该 DLL 神经网络的示例的文件。在我们的示例中,它是 Visual C++ 6 项目。
在上一章创建的 DLL 神经网络旨在用于 Visual C++ 项目。它操作具有复杂结构的对象,而这样的对象难以甚至不可能通过 MQL5 进行描述。这就是我们没有直接将此 DLL 连接至 MetaTrader 的原因。而我们准备创建一个较小的 DLL 适配程序。该适配程序将包含一个用于使用神经网络的简单函数。它将创建神经网络,向其传递输入信息并返回输出数据。
该适配程序将很容易从 MetaTrader 5 调用,并且它将连接至在 NeuroSolutions 中创建的 DLL 神经网络。由于适配网络以 Visual C++ 编写,因此它不会和该 DLL 的对象发生任何冲突。
但如果您有 C++ 编程经验,并且您对如何创建这样的适配程序感兴趣,请读完本章。也许,您会有兴趣去改善该程序,因为一些其他的功能可以从 DLL 神经网络导出。例如,训练功能(针对“EA 交易”,使之适应瞬息万变的市场,自动重新训练神经网络)。您可以通过分析在上一章介绍的由“自定义解决方案向导”生成的示例来了解完整功能列表。
我们仅需要该示例中的几个文件。
在 Visual C++(与“自定义解决方案向导”中使用的版本相同)中,创建一个名为 NeuroSolutionsAdapter 的空 DLL 项目,并从示例将 NSNetwork.h、NSNetwork.cpp 和 StdAfx.h 文件复制到该项目。同时创建一个空的 main.cpp 文件:
在 main.cpp 文件中写入以下代码:
#include "stdafx.h" #include "NSNetwork.h" extern "C" __declspec(dllexport) int __stdcall CalcNeuralNet( LPCWSTR dllPath_u, LPCWSTR weightsPath_u, double* inputs, double* outputs) { // Transform the lines from Unicode to normal ones CString dllPath (dllPath_u); CString weightsPath (weightsPath_u); // Create neuronet NSRecallNetwork nn(dllPath); if (!nn.IsLoaded()) return (1); // Load balances if (nn.LoadWeights(weightsPath) != 0) return (2); // Pass input data and calculate the output if (nn.GetResponse(1, inputs, outputs) != 0) return (3); return 0; }
编译。DLL 适配程序就绪!
至此,我们已创建了多个文件。我将列出这些“EA 交易”工作所需的文件,以及您应该将它们放入的文件夹。所有文件均已附于本文。
文件 | 描述 | 存放路径(终端文件夹中) |
---|---|---|
WeekPattern.dll | 我们在 NeuroSolutions 中创建的 DLL 神经网络 | MQL5\Files\NeuroSolutions\ |
WeekPattern.nsw | 神经网络的平衡设置 | MQL5\Files\NeuroSolutions\ |
NeuroSolutionsAdapter.dll | 可用于任何 DLL 神经网络的通用 DLL 适配程序 | MQL5\Libraries\ |
以下是完整的“EA 交易”WeekPattern.mq5 的代码。为便于搜寻和进一步修改,与神经网络相关的一切已放在单独的 CNeuroSolutionsNeuralNet 类中。
input double Lots = 0.1; //+------------------------------------------------------------------+ // Connect the DLL adapter, using which we are going to use the DLL neuronet created in NeuroSolutions #import "NeuroSolutionsAdapter.dll" int CalcNeuralNet(string dllPath, string weightsPath, double& inputs[], double& outputs[]); #import //+------------------------------------------------------------------+ class CNeuroSolutionsNeuralNet { private: string dllPath; // Path to a DLL neuronet created in NeuroSolutions string weightsPath; // Path to a file of the neuronet balances public: double in[20]; // Neuronet inputs - OHLC of 5 bars double out[1]; // Neuronet outputs - Close of a current bar CNeuroSolutionsNeuralNet(); bool Calc(); }; //+------------------------------------------------------------------+ void CNeuroSolutionsNeuralNet::CNeuroSolutionsNeuralNet() { string terminal = TerminalInfoString(TERMINAL_PATH); dllPath = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.dll"; weightsPath = terminal + "\\MQL5\\Files\\NeuroSolutions\\WeekPattern.nsw"; } //+------------------------------------------------------------------+ bool CNeuroSolutionsNeuralNet::Calc() { // Get current quotes for the neuronet MqlRates rates[], rate; CopyRates(Symbol(), Period(), 0, 6, rates); ArraySetAsSeries(rates, true); // Fill the array of input data of the neuronet double zlevel=0; for (int bar=0; bar<=5; bar++) { rate = rates[bar]; // 0 bar is not taken for input if (bar==0) zlevel=rate.open; // level of price calculation // 1-5 bars are inputed else { int i=(bar-1)*4; // input number in[i ] = rate.open -zlevel; in[i+1] = rate.high -zlevel; in[i+2] = rate.low -zlevel; in[i+3] = rate.close-zlevel; } } // Calculate the neuronet in the NeuroSolutions DLL (though the DLL adapter) int res = CalcNeuralNet(dllPath, weightsPath, in, out); switch (res) { case 1: Print("Error of creating neuronet from DLL \"", dllPath, "\""); return (false); case 2: Print("Error of loading balances to neuronet from the file \"", weightsPath, "\""); return (false); case 3: Print("Error of calculation of neuronet"); return (false); } // Output of the neuronet has appeared in the array out, you shouldn't do anything with it return (true); } //+------------------------------------------------------------------+ CNeuroSolutionsNeuralNet NN; double Prognoze; //+------------------------------------------------------------------+ #include <Trade\Trade.mqh> //+------------------------------------------------------------------+ void OnTick() { // Get the price prediction from the neuronet if (NN.Calc()) Prognoze = NN.out[0]; else Prognoze = 0; // Perform necessary trade actions Trade(); } //+------------------------------------------------------------------+ void Trade() { // Close an open position if it is opposite to the prediction if(PositionSelect(_Symbol)) { long type=PositionGetInteger(POSITION_TYPE); bool close=false; if((type == POSITION_TYPE_BUY) && (Prognoze <= 0)) close = true; if((type == POSITION_TYPE_SELL) && (Prognoze >= 0)) close = true; if(close) { CTrade trade; trade.PositionClose(_Symbol); } } // If there is no positions, open one according to the prediction if((Prognoze!=0) && (!PositionSelect(_Symbol))) { CTrade trade; if(Prognoze > 0) trade.Buy (Lots); if(Prognoze < 0) trade.Sell(Lots); } } //+------------------------------------------------------------------+
一个检查我们是否正确连接神经网络的好方法是,在策略测试程序中运行“EA 交易”——采用与训练神经网络所使用的同一时间周期。
好吧,有经验的交易人员要说了,该神经网络是此周期的“适配程序”。因此它被训练为针对那些确切的数据模式(主导特定的周期)识别和通知获利信号。针对这样一段时间绘制的“EA 交易”的盈利图应该是上升的。
我们来检查一下。在我们的示例中,它应该是如下的漂亮图形:
这表示一切连接正确。
至于统计数据,下面附上了“EA 交易”测试的其他报告:
为防万一,我来为开发新人解释一下交易策略和神经网络。
用于自身优化(训练其神经网络)的某个周期的“EA 交易”的盈利能力,不会反映该 EA 的总体盈利能力。换言之,它不保证自己在其他周期上的盈利能力。其他周期可以有其他的主导模式。
创建盈利能力紧随训练周期的交易策略是一项十分复杂的任务。您不能指望 NeuroSolutions 或任何其他神经网络应用程序可以为您解决这个问题。它只能为您的数据创建神经网络。以上这些就是我没有在此给出获得的“EA 交易”的前瞻性测试的结果的原因。创建一个盈利的交易策略不是本文的目标。本文的目的是告诉读者如何将神经网络连接至“EA 交易”。
现在,交易人员有了另一款强大且易用的工具用于自动交易分析和交易。结合对神经网络原理和功能的深刻理解以及训练它们的准则来使用神经网络,将使您在创建盈利“EA 交易”的道路上飞速前进。