外汇EA编写教程:基于元交易者5指数和Encog机器学习框架的时间序列预测

简介

本文将介绍如何将MetaTrader 5连接到由Heaton Research开发的EnCG高级神经网络和机器学习框架。我知道MetaTrader有一些方法可以使用我之前讨论过的机器学习技术:fann、neuro solutions、matlab和neuro shell。我希望encog是一个补充的解决方案,因为它是可靠、可靠和设计良好的代码。

我为什么选择Encog?有几个原因。

  1. encog已经应用于另外两个商业交易软件包中。一个是以C为基础的,另一个是基于Java的。这意味着它已经被测试来预测财务时间序列数据。
  2. encog是一个免费的开源软件。如果你想知道神经网络中发生了什么,你可以浏览源代码。这是我理解时间序列预测问题的实际工作。C是一种清晰易懂的编程语言。
  3. Encog有完整的文档。Heaton Research的创始人希顿先生提供了关于神经网络、机器学习和使用EnCG预测未来数据的免费在线课程。在写这篇文章之前,我参加了他的许多课程。他们在理解人工神经网络方面帮助了我很多。此外,还有关于用Java和Engon研究EnCOG编程的电子书。完整的编码说明可以在线获得。
  4. encog不是停止维护的项目。在编写时,Encog2.6仍在开发中。最近发布了Encog3.0路线图。
  5. Encog非常强大。它设计良好,可以使用多个CPU内核和多线程加速神经网络计算。部分代码开始专门为支持GPU计算的OpenCL移植。
  6. ECNOG目前支持以下功能:

机器学习类型

  • 前馈和简单递归(埃尔曼/乔丹)
  • 遗传算法
  • 整洁的
  • 概率神经网络/广义回归神经网络(PNN/GRNN)
  • 自组织映射(som/kohonen)
  • 模拟退火算法
  • 支持向量机

神经网络体系结构

  • Adaline神经网络
  • 自适应共振理论1(art1)
  • 双向联想存储器
  • 玻尔兹曼机器
  • 反向传播神经网络
  • 埃尔曼递归神经网络
  • 前馈神经网络(感知器)
  • Hopfield神经网络
  • 约旦递归神经网络
  • 增量拓扑神经进化
  • 径向基函数网络
  • 递归自组织映射(RSOM)
  • 自组织映射(Kohonen)

训练技术

  • 反向传播
  • 弹性传播
  • 定量共轭梯度
  • 曼哈顿更新规则发布
  • 竞争性学习
  • 霍普菲尔德学习
  • Levenberg-Marquart算法(LMA)
  • 遗传算法训练
  • 明星培训
  • 外星训练
  • Adaline培训
  • 训练数据模型
  • 被监督的
  • 无监督的
  • 时间(预测)
  • 财务(从雅虎财务下载)
  • SQL
  • XML
  • 猪瘟病毒
  • 图像还原采样

激活函数

  • 竞争功能
  • 乙状结肠功能
  • 坦赫
  • 线性函数
  • SoftMax函数
  • 切线函数
  • 正弦波函数
  • 阶跃函数
  • 双极性函数
  • 高斯函数

随机化技术

  • 范围随机化
  • 高斯随机数
  • 扇入
  • 阮维德

本计划的功能如下:

  • 超洁的
  • RBN/深层信念
  • 脉冲神经网络

如您所见,这是一个相当长的特性列表。

本文介绍了弹性传播(RPROP)训练的前馈神经网络结构。它还包括数据编译的基础——时间序列预测的时间量化和规范化。

使我能够撰写这篇文章的知识是基于《希顿研究》提供的教程和《忍者商人》最近关于预测金融时间系列的文章。请注意,EnCOG是基于Java和C语言的。如果没有我以前的文章“使用非托管导出将C代码应用于MQL5”,就不可能编写本文。此解决方案使使用C_DLL作为metatrader 5和encog时间序列预测程序之间的桥梁成为可能。

1。以技术指标值作为神经网络的输入

人工神经网络(ANN)是一种试图模拟大脑神经网络的人机工程学算法。

有各种各样的神经算法可用,也有各种各样的神经网络结构。研究领域十分广泛,对各种神经网络分别进行了专门的介绍。因为这些细节超出了本文的范围,所以我只能建议您阅读关于相关主题的Heaton研究教程或书籍。我将重点介绍前馈神经网络的输入和输出,并尝试描述金融时间序列预测的例子。

为了开始预测金融时间序列,我们必须考虑我们应该向神经网络提供什么,以及我们从中期望什么。在最抽象的黑箱思想中,我们通过长期或短期的指定证券合约来实现盈亏,并在一段时间后平仓。

通过观察投资组合的过去价格和技术指标的价值,我们试图预测未来的市场情绪和价格方向,买卖合同,并确保我们的决策不是通过抛硬币作出的。情况或多或少类似于下图:

图 1. 使用技术指标预测金融时间序列

图1。用技术指标预测财务时间序列-nbsp;

我们将努力用人工智能取得同样的成果。神经网络将尝试识别指数值,并确定价格是否有上升或下降的机会。我们如何才能实现这个目标?由于我们将使用前馈神经网络结构来预测金融时间序列,我认为我们需要介绍它的结构。

前馈神经网络由神经元分层组成。必须至少有两层:包含输入神经元的输入层和包含输出神经元的输出层。在输入层和输出层之间也可以有一个隐藏层。输入层可以简单地看作双精度值数组,而输出层可以由一个或多个同时构成双精度值数组的神经元组成。见下图:

 图 2. 前馈神经网络层

图2。前馈神经网络层

为了简化作图,神经元之间没有联系。输入层中的每个神经元都与隐藏层中的一个神经元相连。隐藏层中的每个神经元都连接到输入层中的一个神经元。

每个连接都有它的权重,这也是一个双精度值,以及一个阈值激活功能,负责激活神经元并将信息传递给下一个神经元。这就是为什么它被称为前馈网络——基于激活神经元输出的信息从一层神经元向前传输到另一层。有关前馈神经网络的详细视频介绍,请单击以下链接:

  • 神经网络计算(第1部分):前馈结构
  • 神经网络计算(第2部分):激活函数与基础计算
  • 神经网络计算(第3部分):前馈神经网络计算

在你理解了神经网络的结构和机制之后,你可能仍然困惑。

主要问题包括:

  1. 我们应该向神经网络提供什么数据?
  2. 我们如何提供?
  3. 如何为神经网络准备输入数据?
  4. 如何选择神经网络结构?我们需要多少输入神经元、隐藏神经元和输出神经元?
  5. 如何训练网络?
  6. 预期产量是多少?

nbsp;

2。应该向神经网络提供什么数据?

由于我们是以指标产出为基础进行财务预测的,所以我们应该为网络提供指标产出值。对于本文,我选择随机索引%k、随机慢索引%d和威廉索引%r作为输入。

图 3. 用于预测的技术指标

图3。预测技术指标

为了提取索引的值,我们可以使用istochastic和iwpr mql5函数:

double StochKArr[], StochDArr[], WilliamsRArr[];

ArraySetAsSeries(StochKArr, true);   
ArraySetAsSeries(StochDArr, true);   
ArraySetAsSeries(WilliamsRArr, true);

int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
CopyBuffer(hStochastic, 0, 0, bufSize, StochKArr);
CopyBuffer(hStochastic, 1, 0, bufSize, StochDArr);
CopyBuffer(hWilliamsR, 0, 0, bufSize, WilliamsRArr);

执行完这段代码后,三个数组stochkarr、stochdarr和williams rarr应该用度量的输出值填充。根据培训样本的大小,它可能多达几千个值。请记住,这两个指标仅用于教育目的。

建议测试任何适合预测的指标。您可能需要向网络提供黄金和原油价格来预测股票指数,或者您可以使用相关的外汇货币对来预测另一种货币对。

nbsp;

三。时间定量输入数据

在从多个指标收集输入数据后,我们需要在将输入时间框提供给神经网络之前对其进行量化。Timeboxing是一种允许作为移动数据片段输入到网络的技术。您可以想象一个输入数据移动框在时间线上向前移动。这个过程主要包括两个步骤:

1。从每个指示器缓存收集输入数据。我们需要从开始到将来复制输入窗口元素。输入窗口是用于预测的列数。

 图 4. 从指标缓存收集输入窗口数据

图4。从索引缓存收集输入窗口数据-nbsp;

如上例所示,input_window等于四列,我们将元素复制到i1数组。I1[0]是第一个元素,I1[3]是最后一个元素。同样,必须将数据从其他度量复制到大小输入窗口的数组中。此数字对时间序列数组有效,其中as_series标记设置为true。

2。结合输入窗口的数目,为神经网络的输入层提供一个数组。

图 5. 时间定量后的输入窗口数组

图5。时间量化后的输入窗口数组

有三个指标。首先,我们取每个指标的第一个值,然后取每个指标的第二个值,直到输入窗口被填满,如上图所示。从索引输出的组合数组可以提供给神经网络的输入层。当新列到达时,数据被一个元素一个元素地分割,整个过程被重复。如果您有兴趣在准备过程中了解更多有关预测数据的信息,还可以观看有关主题的视频。

nbsp;

4。输入数据的规范化

为了使神经网络有效运行,必须对数据进行归一化处理。这是正确计算激活功能所必需的。规范化是一个将数据转换为0.1或-1.1范围的数学过程。归一化数据可以进行非归一化,即转换回原始范围。

为了将神经网络的输出解码为人类可读的形式,有必要对数据进行去规范化。值得庆幸的是,Encog负责标准化和去标准化,因此不需要实施。如果您对它的工作方式很好奇,可以分析以下代码:

/**
         * Normalize the specified value.
         * @param value The value to normalize.
         * @return The normalized value.
         */
        public static double normalize(final int value) {
                return ((value - INPUT_LOW) 
                                / (INPUT_HIGH - INPUT_LOW))
                                * (OUTPUT_HIGH - OUTPUT_LOW) + OUTPUT_LOW;
        }
        
        /**
         * De-normalize the specified value.
         * @param value The value to denormalize.
         * @return The denormalized value.
         */
        public static double deNormalize(final double data) {
                double result = ((INPUT_LOW - INPUT_HIGH) * data - OUTPUT_HIGH
                                * INPUT_LOW + INPUT_HIGH * OUTPUT_LOW)
                                / (OUTPUT_LOW - OUTPUT_HIGH);
                return result;
        }

阅读有关规范化的文章以获取更多信息。

nbsp;

5。选择网络架构和神经元数量

对于这个主题的新手来说,选择正确的网络体系结构是一个困难的任务。本文将前馈神经网络的结构限定为三层:输入层、隐藏层和输出层。你可以随意尝试更多的层。

对于输入和输出层,我们可以精确计算所需的神经元数量。对于隐藏层,我们将尝试通过正向选择算法最小化神经网络误差。建议您使用其他方法;可能有一些遗传算法来计算神经元的数量。

encog使用的另一种方法称为反向选择或修剪。它基本上评估了各层之间的连接,并以零连接权重移除隐藏的神经元。你可能想试试。

5.1。输入神经元层

由于时间量化,输入层中的神经元数量应等于指标数量乘以用于预测下一列的列数。如果我们使用三个指示器作为输入,并且输入窗口的大小等于六列,那么输入层将包含18个神经元。输入层及时提供定量准备的数据。

5.2。隐藏神经元层

隐网络的数目必须根据训练后的神经网络的性能来估计。隐藏神经元的数量没有直接的数学方程。在写这篇文章之前,我使用了各种尝试和错误方法,并在Heaton Research上找到了一种有助于理解正向选择算法的算法:

图 6. 用于计算隐藏神经元数量的前向选择算法

图6。计算隐藏神经元数量的正向选择算法

5.3。输出神经元层

出于我们的目的,输出神经元的数量等于我们试图预测的列的数量。请记住,隐藏和输出神经元的数量越多,网络训练时间越长。在本文中,我试图预测未来的支柱,因此输出层包含一个神经元。

nbsp;

6。将培训数据从metatrader 5导出到encog

encog接收用于神经网络训练的csv文件。

我查看了从其他交易软件导出到encog的文件格式,并实现了为培训准备相同文件格式的MQL5脚本。我将从引入和导出一个指标开始,然后转到几个指标。

第一行数据是逗号分隔的标题:

DATE,TIME,CLOSE,Indicator_Name1,Indicator_Name2,Indicator_Name3

前三列包含日期、时间和收盘价,下一列包含索引名。培训文件的下一行应包含逗号分隔的数据,索引值应采用科学的计数方法表示:

20110103,0000,0.93377000,-7.8970208860e-002

为一个指标查看以下现成的脚本。

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 400;
extern int  maPeriod = 210;

MqlRates srcArr[];
double expBullsArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(expBullsArr, true);      
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hBullsPower = iBullsPower(Symbol(), Period(), maPeriod);
   
   CopyBuffer(hBullsPower, 0, 0, trainSize, expBullsArr);
   
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,BullsPower/n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), DoubleToString(expBullsArr[i], -10));
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

&可用于培训的结果文件应如下所示:

DATE,TIME,CLOSE,BullsPower
20110103,0000,0.93377000,-7.8970208860e-002
20110104,0000,0.94780000,-6.4962292188e-002
20110105,0000,0.96571000,-4.7640374727e-002
20110106,0000,0.96527000,-4.4878854587e-002
20110107,0000,0.96697000,-4.6178012364e-002
20110110,0000,0.96772000,-4.2078647318e-002
20110111,0000,0.97359000,-3.6029181466e-002
20110112,0000,0.96645000,-3.8335729509e-002
20110113,0000,0.96416000,-3.7054869514e-002
20110114,0000,0.96320000,-4.4259373120e-002
20110117,0000,0.96503000,-4.4835729773e-002
20110118,0000,0.96340000,-4.6420936126e-002
20110119,0000,0.95585000,-4.6868984125e-002
20110120,0000,0.96723000,-4.2709941621e-002
20110121,0000,0.95810000,-4.1918330800e-002
20110124,0000,0.94873000,-4.7722659418e-002
20110125,0000,0.94230000,-5.7111591557e-002
20110126,0000,0.94282000,-6.2231529077e-002
20110127,0000,0.94603000,-5.9997865295e-002
20110128,0000,0.94165000,-6.0378312069e-002
20110131,0000,0.94414000,-6.2038328069e-002
20110201,0000,0.93531000,-6.0710334438e-002
20110202,0000,0.94034000,-6.1446445012e-002
20110203,0000,0.94586000,-5.2580791504e-002
20110204,0000,0.95496000,-4.5246755566e-002
20110207,0000,0.95730000,-4.4439392954e-002

回到使用随机度量和威廉度量的原始文章示例,我们需要导出三个逗号分隔的列,每个列包含一个单独的度量值,因此我们需要展开文件并添加其他缓存:

//+------------------------------------------------------------------+
//|                                                ExportToEncog.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+

// Export Indicator values for NN training by ENCOG
extern string IndExportFileName = "mt5export.csv";
extern int  trainSize = 2000;

MqlRates srcArr[];
double StochKArr[], StochDArr[], WilliamsRArr[];

void OnStart()
  {
//---
   ArraySetAsSeries(srcArr, true);   
   ArraySetAsSeries(StochKArr, true);   
   ArraySetAsSeries(StochDArr, true);   
   ArraySetAsSeries(WilliamsRArr, true);
         
   int copied = CopyRates(Symbol(), Period(), 0, trainSize, srcArr);
   
   if (copied!=trainSize) { Print("Not enough data for " + Symbol()); return; }
   
   int hStochastic = iStochastic(Symbol(), Period(), 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   int hWilliamsR = iWPR(Symbol(), Period(), 21);
   
   
   CopyBuffer(hStochastic, 0, 0, trainSize, StochKArr);
   CopyBuffer(hStochastic, 1, 0, trainSize, StochDArr);
   CopyBuffer(hWilliamsR, 0, 0, trainSize, WilliamsRArr);
    
   int hFile = FileOpen(IndExportFileName, FILE_CSV | FILE_ANSI | FILE_WRITE | FILE_REWRITE, ",", CP_ACP);
   
   FileWriteString(hFile, "DATE,TIME,CLOSE,StochK,StochD,WilliamsR/n");
   
   Print("Exporting indicator data to " + IndExportFileName);
   
   for (int i=trainSize-1; i>=0; i--)
      {
         string candleDate = TimeToString(srcArr[i].time, TIME_DATE);
         StringReplace(candleDate,".","");
         string candleTime = TimeToString(srcArr[i].time, TIME_MINUTES);
         StringReplace(candleTime,":","");
         FileWrite(hFile, candleDate, candleTime, DoubleToString(srcArr[i].close), 
                                                 DoubleToString(StochKArr[i], -10),
                                                 DoubleToString(StochDArr[i], -10),
                                                 DoubleToString(WilliamsRArr[i], -10)
                                                 );
      }
      
   FileClose(hFile);   
     
   Print("Indicator data exported."); 
  }
//+------------------------------------------------------------------+

结果文件应包含所有指标:

DATE,TIME,CLOSE,StochK,StochD,WilliamsR
20030707,0000,1.37370000,7.1743119266e+001,7.2390220187e+001,-6.2189054726e-001
20030708,0000,1.36870000,7.5140977444e+001,7.3307139273e+001,-1.2500000000e+001
20030709,0000,1.35990000,7.3831775701e+001,7.3482018082e+001,-2.2780373832e+001
20030710,0000,1.36100000,7.1421933086e+001,7.2795323083e+001,-2.1495327103e+001
20030711,0000,1.37600000,7.5398313027e+001,7.3662986398e+001,-3.9719626168e+000
20030714,0000,1.37370000,7.0955352856e+001,7.2760441884e+001,-9.6153846154e+000
20030715,0000,1.38560000,7.4975891996e+001,7.3498925255e+001,-2.3890784983e+000
20030716,0000,1.37530000,7.5354107649e+001,7.4117319386e+001,-2.2322435175e+001
20030717,0000,1.36960000,7.1775345074e+001,7.3336661282e+001,-3.0429594272e+001
20030718,0000,1.36280000,5.8474576271e+001,6.8382632945e+001,-3.9778325123e+001
20030721,0000,1.35400000,4.3498596819e+001,6.0087954237e+001,-5.4946524064e+001
20030722,0000,1.36130000,2.9036761284e+001,4.9737556586e+001,-4.5187165775e+001
20030723,0000,1.34640000,1.6979405034e+001,3.8818172735e+001,-6.5989159892e+001
20030724,0000,1.34680000,1.0634573304e+001,2.9423639592e+001,-7.1555555556e+001
20030725,0000,1.34400000,9.0909090909e+000,2.2646062758e+001,-8.7500000000e+001
20030728,0000,1.34680000,1.2264922322e+001,1.9185682613e+001,-8.2705479452e+001
20030729,0000,1.35250000,1.4960629921e+001,1.7777331716e+001,-7.2945205479e+001
20030730,0000,1.36390000,2.7553336360e+001,2.1035999930e+001,-5.3979238754e+001
20030731,0000,1.36990000,4.3307839388e+001,2.8459946416e+001,-4.3598615917e+001
20030801,0000,1.36460000,5.6996412096e+001,3.7972101643e+001,-5.2768166090e+001
20030804,0000,1.34780000,5.7070193286e+001,4.4338132191e+001,-8.1833910035e+001
20030805,0000,1.34770000,5.3512705531e+001,4.7396323304e+001,-8.2006920415e+001
20030806,0000,1.35350000,4.4481132075e+001,4.6424592894e+001,-7.1972318339e+001
20030807,0000,1.35020000,3.3740028156e+001,4.2196404648e+001,-7.7681660900e+001
20030808,0000,1.35970000,3.0395426394e+001,3.8262745230e+001,-6.1245674740e+001
20030811,0000,1.35780000,3.4155781326e+001,3.6893757262e+001,-6.4532871972e+001
20030812,0000,1.36880000,4.3488943489e+001,3.9092152671e+001,-4.5501730104e+001
20030813,0000,1.36690000,5.1160443996e+001,4.3114916446e+001,-4.8788927336e+001
20030814,0000,1.36980000,6.2467599793e+001,4.9565810895e+001,-2.5629290618e+001
20030815,0000,1.37150000,6.9668246445e+001,5.6266622745e+001,-2.1739130435e+001
20030818,0000,1.38910000,7.9908906883e+001,6.4147384124e+001,-9.2819614711e+000

您可以修改第二个示例,以便轻松生成满足您需求的脚本。

7。神经网络训练

Heaton Research使用C为网络准备培训。encog 2.6实现了encog。应用程序。定量名称空间,是财务时间序列预测的基础。培训脚本非常灵活,可以很容易地调整到任何数量的输入指标。您应该只在目录常量中更改metatrader 5目录的位置。

您可以通过更改以下变量轻松自定义网络架构和培训参数:

        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

代码包含非常完整的解释,因此最好仔细阅读代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Encog.App.Quant.Normalize;
using Encog.Util.CSV;
using Encog.App.Quant.Indicators;
using Encog.App.Quant.Indicators.Predictive;
using Encog.App.Quant.Temporal;
using Encog.Neural.NeuralData;
using Encog.Neural.Data.Basic;
using Encog.Util.Simple;
using Encog.Neural.Networks;
using Encog.Neural.Networks.Layers;
using Encog.Engine.Network.Activation;
using Encog.Persist;

namespace NetworkTrainer
{
    public class Program
    {
        /// <summary>
        /// The directory that all of the files will be stored in.
        /// </summary>
        public const String DIRECTORY = "d://mt5//MQL5//Files//";

        /// <summary>
        /// The input file that starts the whole process.  This file should be downloaded from NinjaTrader using the EncogStreamWriter object.
        /// </summary>
        public const String STEP1_FILENAME = DIRECTORY + "mt5export.csv";

        /// <summary>
        /// We apply a predictive future indicator and generate a second file, with the additional predictive field added.
        /// </summary>
        public const String STEP2_FILENAME = DIRECTORY + "step2_future.csv";

        /// <summary>
        /// Next the entire file is normalized and stored into this file.
        /// </summary>
        public const String STEP3_FILENAME = DIRECTORY + "step3_norm.csv";

        /// <summary>
        /// The file is time-boxed to create training data.
        /// </summary>
        public const String STEP4_FILENAME = DIRECTORY + "step4_train.csv";

        /// <summary>
        /// Finally, the trained neural network is written to this file.
        /// </summary>
        public const String STEP5_FILENAME = DIRECTORY + "step5_network.eg";
       
        /// <summary>
        /// The size of the input window.  This is the number of bars used to predict the next bar.
        /// </summary>
        public const int INPUT_WINDOW = 6;        

        /// <summary>
        /// The number of bars forward we are trying to predict.  This is usually just 1 bar.  The future indicator used in step 1 may
        /// well look more forward into the future. 
        /// </summary>
        public const int PREDICT_WINDOW = 1;

        /// <summary>
        /// The number of bars forward to look for the best result.
        /// </summary>
        public const int RESULT_WINDOW = 5;

        /// <summary>
        /// The number of neurons in the first hidden layer.
        /// </summary>
        public const int HIDDEN1_NEURONS = 12;

        /// <summary>
        /// The target error to train to.
        /// </summary>
        public const double TARGET_ERROR = 0.01;

        static void Main(string[] args)
        {
            // Step 1: Create future indicators
            Console.WriteLine("Step 1: Analyze MT5 Export & Create Future Indicators");
            ProcessIndicators ind = new ProcessIndicators();
            ind.Analyze(STEP1_FILENAME, true, CSVFormat.DECIMAL_POINT);
            int externalIndicatorCount = ind.Columns.Count - 3;
            ind.AddColumn(new BestReturn(RESULT_WINDOW,true)); 
            ind.Process(STEP2_FILENAME);          
            Console.WriteLine("External indicators found: " + externalIndicatorCount);
            //Console.ReadKey();

            // Step 2: Normalize
            Console.WriteLine("Step 2: Create Future Indicators");
            EncogNormalize norm = new EncogNormalize();
            norm.Analyze(STEP2_FILENAME, true, CSVFormat.ENGLISH);
            norm.Stats[0].Action = NormalizationDesired.PassThrough; // Date
            norm.Stats[1].Action = NormalizationDesired.PassThrough; // Time
            
            norm.Stats[2].Action = NormalizationDesired.Normalize; // Close
            norm.Stats[3].Action = NormalizationDesired.Normalize; // Stoch K
            norm.Stats[4].Action = NormalizationDesired.Normalize; // Stoch Dd
            norm.Stats[5].Action = NormalizationDesired.Normalize; // WilliamsR
       
            norm.Stats[6].Action = NormalizationDesired.Normalize; // best return [RESULT_WINDOW]

            norm.Normalize(STEP3_FILENAME);

            // neuron counts
            int inputNeurons = INPUT_WINDOW * externalIndicatorCount;
            int outputNeurons = PREDICT_WINDOW;

            // Step 3: Time-box
            Console.WriteLine("Step 3: Timebox");
            //Console.ReadKey();
            TemporalWindow window = new TemporalWindow();
            window.Analyze(STEP3_FILENAME, true, CSVFormat.ENGLISH);
            window.InputWindow = INPUT_WINDOW;
            window.PredictWindow = PREDICT_WINDOW;
            int index = 0;
            window.Fields[index++].Action = TemporalType.Ignore; // date
            window.Fields[index++].Action = TemporalType.Ignore; // time
            window.Fields[index++].Action = TemporalType.Ignore; // close
            for(int i=0;i<externalIndicatorCount;i++)
                window.Fields[index++].Action = TemporalType.Input; // external indicators
            window.Fields[index++].Action = TemporalType.Predict; // PredictBestReturn

            window.Process(STEP4_FILENAME);

            // Step 4: Train neural network
            Console.WriteLine("Step 4: Train");
            Console.ReadKey();
            INeuralDataSet training = (BasicNeuralDataSet)EncogUtility.LoadCSV2Memory(STEP4_FILENAME, inputNeurons, 
                                                                                      outputNeurons, true, CSVFormat.ENGLISH);

            BasicNetwork network = new BasicNetwork();
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, inputNeurons));
            network.AddLayer(new BasicLayer(new ActivationTANH(), true, HIDDEN1_NEURONS));
            network.AddLayer(new BasicLayer(new ActivationLinear(), true, outputNeurons));
            network.Structure.FinalizeStructure();
            network.Reset();

            //EncogUtility.TrainToError(network, training, TARGET_ERROR);
            EncogUtility.TrainConsole(network, training, 3);

            // Step 5: Save neural network and stats
            EncogMemoryCollection encog = new EncogMemoryCollection();
            encog.Add("network", network);
            encog.Add("stat", norm.Stats);
            encog.Save(STEP5_FILENAME);
            Console.ReadKey();
        }
    }
}

你可能会注意到我评论了一句话,把训练功能从鼓励改了。训练错误()到鼓励性。trainconsole()。

EncogUtility.TrainConsole(network, training, 3);

trainconsole方法指定培训网络的分钟数。在这个例子中,我训练网络三分钟。根据网络的复杂性和培训数据的大小,培训网络可能需要几分钟、几小时甚至几天的时间。我建议更详细地理解关于希顿研究的误差计算和训练算法,或者在任何其他有关主题的书中。

鼓励性。traintoError()方法在到达目标网络错误后停止网络训练。你可以用注释来解释。trainconsole()并取消“鼓励性”注释。traintoError()将网络训练为所需的错误,如原始示例中所示。

EncogUtility.TrainToError(network, training, TARGET_ERROR);

注意,有时由于神经元数量少,网络可能不会被训练成一定的错误。

8。利用训练神经网络建立元交易者5神经指标

训练后的网络可以作为神经网络指标,试图预测投资的最佳回报。

MetaTrader 5的Encog神经指数由两部分组成。其中一部分是用MQL5编写的,它使用与培训网络相同的索引,并向网络提供输入窗口索引值。第二部分用C编写,它量化输入数据的时间,并将神经网络的输出返回到MQL5。C Indicators部分基于我之前关于“将C代码应用于MQL5”的文章。

using System;
using System.Collections.Generic;
using System.Text;
using RGiesecke.DllExport;
using System.Runtime.InteropServices;
using Encog.Neural.Networks;
using Encog.Persist;
using Encog.App.Quant.Normalize;
using Encog.Neural.Data;
using Encog.Neural.Data.Basic;

namespace EncogNeuralIndicatorMT5DLL
{

    public class NeuralNET
    {
        private EncogMemoryCollection encog;
        public BasicNetwork network;
        public NormalizationStats stats;

        public NeuralNET(string nnPath)
        {
            initializeNN(nnPath);
        }

        public void initializeNN(string nnPath)
        {
            try
            {
                encog = new EncogMemoryCollection();
                encog.Load(nnPath);
                network = (BasicNetwork)encog.Find("network");
                stats = (NormalizationStats)encog.Find("stat");
            }
            catch (Exception e)
            {
                Console.WriteLine(e.StackTrace);
            }
        }
    };

   class UnmanagedExports
   {

      static NeuralNET neuralnet; 

      [DllExport("initializeTrainedNN", CallingConvention = CallingConvention.StdCall)]
      static int initializeTrainedNN([MarshalAs(UnmanagedType.LPWStr)]string nnPath)
      {
          neuralnet = new NeuralNET(nnPath);

          if (neuralnet.network != null) return 0;
          else return -1;
      }

      [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                           [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                           int len, 
                                           [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                           int rates_total)
      {
          INeuralData input = new BasicNeuralData(3 * len);
          
          int index = 0;
          for (int i = 0; i <len; i++)
          {
              input[index++] = neuralnet.stats[3].Normalize(t1[i]);
              input[index++] = neuralnet.stats[4].Normalize(t2[i]);
              input[index++] = neuralnet.stats[5].Normalize(t3[i]);
          }

          INeuralData output = neuralnet.network.Compute(input);
          double d = output[0];
          d = neuralnet.stats[6].DeNormalize(d);        
          result[rates_total-1]=d;

          return 0;
      }  
   }
}

如果您喜欢使用除三个以外的任何数量的度量,则需要更改ComputenIndicator()方法以满足您的需要。

 [DllExport("computeNNIndicator", CallingConvention = CallingConvention.StdCall)]
      public static int computeNNIndicator([MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t1,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t2,
                                         [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 3)] double[] t3, 
                                         int len, 
                                         [In, Out, MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 5)] double[] result,
                                         int rates_total)

在这种情况下,前三个输入参数是包含索引输入值的表,第四个参数是输入窗口的长度。

sizeParamIndex=3指向输入窗口长度变量,因为输入变量从零开始计数。第五个参数是包含神经网络结果的表。

mql5 index部分需要导入c encontraindll。并使用从dll派生的initializetrainednn()和computennindicator()函数。

//+------------------------------------------------------------------+
//|                                         NeuralEncogIndicator.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"
#property indicator_separate_window

#property indicator_plots 1
#property indicator_buffers 1
#property indicator_color1 Blue
#property indicator_type1 DRAW_LINE
#property indicator_style1 STYLE_SOLID
#property indicator_width1  2

#import "EncogNNTrainDLL.dll"
   int initializeTrainedNN(string nnFile);
   int computeNNIndicator(double& ind1[], double& ind2[],double& ind3[], int size, double& result[], int rates);  
#import


int INPUT_WINDOW = 6;
int PREDICT_WINDOW = 1;

double ind1Arr[], ind2Arr[], ind3Arr[]; 
double neuralArr[];

int hStochastic;
int hWilliamsR;

int hNeuralMA;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0, neuralArr, INDICATOR_DATA);
   
   PlotIndexSetInteger(0, PLOT_SHIFT, 1);

   ArrayResize(ind1Arr, INPUT_WINDOW);
   ArrayResize(ind2Arr, INPUT_WINDOW);
   ArrayResize(ind3Arr, INPUT_WINDOW);
     
   ArrayInitialize(neuralArr, 0.0);
   
   ArraySetAsSeries(ind1Arr, true);   
   ArraySetAsSeries(ind2Arr, true);  
   ArraySetAsSeries(ind3Arr, true);
  
   ArraySetAsSeries(neuralArr, true);   
               
   hStochastic = iStochastic(NULL, 0, 8, 5, 5, MODE_EMA, STO_LOWHIGH);
   hWilliamsR = iWPR(NULL, 0, 21);
 
   Print(TerminalInfoString(TERMINAL_DATA_PATH)+"//MQL5/Files/step5_network.eg");
   initializeTrainedNN(TerminalInfoString(TERMINAL_DATA_PATH)+"//MQL5/Files/step5_network.eg");
      
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime& time[],
                const double& open[],
                const double& high[],
                const double& low[],
                const double& close[],
                const long& tick_volume[],
                const long& volume[],
                const int& spread[])
  {
//---
   int calc_limit;
   
   if(prev_calculated==0) // First execution of the OnCalculate() function after the indicator start
        calc_limit=rates_total-34; 
   else calc_limit=rates_total-prev_calculated;
    
   ArrayResize(neuralArr, rates_total);
  
   for (int i=0; i<calc_limit; i++)     
   {
      CopyBuffer(hStochastic, 0, i, INPUT_WINDOW, ind1Arr);
      CopyBuffer(hStochastic, 1, i, INPUT_WINDOW, ind2Arr);
      CopyBuffer(hWilliamsR,  0, i, INPUT_WINDOW, ind3Arr);    
      
      computeNNIndicator(ind1Arr, ind2Arr, ind3Arr, INPUT_WINDOW, neuralArr, rates_total-i); 
   }
     
  //Print("neuralArr[0] = " + neuralArr[0]);
  
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+

见使用USDCHF每日数据和随机指标以及威廉指标%r培训的指标输出:

图 7. Encog 神经指标

图7。神经系统指标

指标显示了下一个支柱的最佳预测投资回报。

你可能已经注意到我已经将指示器移到了未来方向的位置:

PlotIndexSetInteger(0, PLOT_SHIFT, 1);

这表示该索引是一个预测值。因为我们构建了一个神经指标,所以我们准备基于该指标构建一个EA事务。

9。基于神经指标的电子交易

EA交易使用神经指标来输出和决定是否购买或出售证券。我的第一个印象是,我们应该在指数大于零的时候买入,在指数小于零的时候卖出,也就是说,我们应该在某个时间窗的最佳回报预测值为正的时候买入,在最佳回报预测值为负的时候卖出。

经过一些初步的测试,我们发现业绩应该更好,所以我介绍了“强上升趋势”和“强下降趋势”的变量,也就是说,根据著名的“趋势是你的朋友”原则,我们没有理由在强趋势下退出市场。

另外,我在Heaton Research Forum上得到了使用ATR进行移动站点的建议,所以我使用了在MQL5 Forum中找到的枝形吊灯ATR索引。在重新测试期间,资产净值确实增加了。我把EA事务的源代码粘贴在下面。

//+------------------------------------------------------------------+
//|                                           NeuralEncogAdvisor.mq5 |
//|                                      Copyright 2011, Investeo.pl |
//|                                                http:/Investeo.pl |
//+------------------------------------------------------------------+
#property copyright "Copyright 2011, Investeo.pl"
#property link      "http:/Investeo.pl"
#property version   "1.00"

double neuralArr[];

double trend;
double Lots=0.3;

int INPUT_WINDOW=8;

int hNeural,hChandelier;

//+------------------------------------------------------------------+
#include <Trade/Trade.mqh>
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   ArrayResize(neuralArr,INPUT_WINDOW);
   ArraySetAsSeries(neuralArr,true);
   ArrayInitialize(neuralArr,0.0);

   hNeural=iCustom(Symbol(),Period(),"NeuralEncogIndicator");
   Print("hNeural = ",hNeural,"  error = ",GetLastError());

   if(hNeural<0)
     {
      Print("The creation of ENCOG indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("ENCOG indicator initialized");

   hChandelier=iCustom(Symbol(),Period(),"Chandelier");
   Print("hChandelier = ",hChandelier,"  error = ",GetLastError());

   if(hChandelier<0)
     {
      Print("The creation of Chandelier indicator has failed: Runtime error =",GetLastError());
      //--- forced program termination
      return(-1);
     }
   else  Print("Chandelier indicator initialized");
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---
   long tickCnt[1];
   int ticks=CopyTickVolume(Symbol(),0,0,1,tickCnt);
   if(tickCnt[0]==1)
     {
      if(!CopyBuffer(hNeural,0,0,INPUT_WINDOW,neuralArr)) { Print("Copy1 error"); return; }

      // Print("neuralArr[0] = "+neuralArr[0]+"neuralArr[1] = "+neuralArr[1]+"neuralArr[2] = "+neuralArr[2]);
      trend=0;

      if(neuralArr[0]<0 && neuralArr[1]>0) trend=-1;
      if(neuralArr[0]>0 && neuralArr[1]<0) trend=1;

      Trade();
     }
  }
//+------------------------------------------------------------------+
//| Tester function                                                  |
//+------------------------------------------------------------------+
double OnTester()
  {
//---

//---
   return(0.0);
  }
//+------------------------------------------------------------------+

void Trade()
  {
   double bufChandelierUP[2];
   double bufChandelierDN[2];

   double bufMA[2];

   ArraySetAsSeries(bufChandelierUP,true);
   ArraySetAsSeries(bufChandelierUP,true);

   ArraySetAsSeries(bufMA,true);

   CopyBuffer(hChandelier,0,0,2,bufChandelierUP);
   CopyBuffer(hChandelier,1,0,2,bufChandelierDN);

   MqlRates rates[];
   ArraySetAsSeries(rates,true);
   int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,3,rates);

   bool strong_uptrend=neuralArr[0]>0 && neuralArr[1]>0 && neuralArr[2]>0 &&
                      neuralArr[3]>0 && neuralArr[4]>0 && neuralArr[5]>0 &&
                       neuralArr[6]>0 && neuralArr[7]>0;
   bool strong_downtrend=neuralArr[0]<0 && neuralArr[1]<0 && neuralArr[2]<0 &&
                        neuralArr[3]<0 && neuralArr[4]<0 && neuralArr[5]<0 &&
                        neuralArr[6]<0 && neuralArr[7]<0;

   if(PositionSelect(_Symbol))
     {
      long type=PositionGetInteger(POSITION_TYPE);
      bool close=false;

      if((type==POSITION_TYPE_BUY) && (trend==-1))

         if(!(strong_uptrend) || (bufChandelierUP[0]==EMPTY_VALUE)) close=true;
      if((type==POSITION_TYPE_SELL) && (trend==1))
         if(!(strong_downtrend) || (bufChandelierDN[0]==EMPTY_VALUE))
            close=true;
      if(close)
        {
         CTrade trade;
         trade.PositionClose(_Symbol);
        }
      else // adjust s/l
        {
         CTrade trade;

         if(copied>0)
           {
            if(type==POSITION_TYPE_BUY)
              {
               if(bufChandelierUP[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierUP[0],0.0);
              }
            if(type==POSITION_TYPE_SELL)
              {
               if(bufChandelierDN[0]!=EMPTY_VALUE)
                  trade.PositionModify(Symbol(),bufChandelierDN[0],0.0);
              }
           }
        }
     }

   if((trend!=0) && (!PositionSelect(_Symbol)))
     {
      CTrade trade;
      MqlTick tick;
      MqlRates rates[];
      ArraySetAsSeries(rates,true);
      int copied=CopyRates(Symbol(),PERIOD_CURRENT,0,INPUT_WINDOW,rates);

      if(copied>0)
        {
         if(SymbolInfoTick(_Symbol,tick)==true)
           {
            if(trend>0)
              {
               trade.Buy(Lots,_Symbol,tick.ask);
               Print("Buy at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
            if(trend<0)
              {
               trade.Sell(Lots,_Symbol,tick.bid);
               Print("Sell at "+tick.ask+" trend = "+trend+" neuralArr = "+neuralArr[0]);
              }
           }
        }
     }

  }
//+------------------------------------------------------------------+

EA交易使用USDCHF货币D1数据。大约50%的数据来自培训样本。

10。EA交易结果

我把测试结果贴在下面。试验所用数据为2000年1月1日至2011年3月26日。

图 8. 神经网络 EA 交易回测结果

图8。神经网络EA交易收益测试结果

图 9. 神经网络 EA 交易余额/资产净值回测图

图9。神经网络EA交易余额/净资产收益图

请注意,对于其他时间框架和其他证券,此性能可能完全不同。

请将此EA视为教育用途,并将其作为进一步研究的起点。我个人的观点是,每次都可以重新训练互联网,使其更强大。有人可能或可能已经找到了实现这一目标的好方法。有一种更好的方法可以根据神经系统指标做出买卖预测。我鼓励读者尝试。

总结

在下面的文章中,我提出了一种利用encog机器学习框架构造神经预测指标和基于该指标的EA事务的方法。本文还包括所有源代码、编译的二进制文件、DLL和可以仿真的经过训练的网络。

cloo.dll、encog-core-cs.dll和log4net.dll文件应位于客户端的文件夹中,因为“双dll打包”。NET“。
encogntrantell.dll文件应位于/terminal data folder/mql5/libraries/folder中。

由MetaQuotes Software Corp.从英文翻译为
原文。https://www.mql5.com/en/articles/252

附加文件下载zip encogschrp.zip(2202.77 kb)files.zip(270.14 kb)libraries.zip(321.62 kb)expert.zip(1.56 kb)scripts.zip(1.03 kb)indicators.zip(2.24 kb)

 

 


MyFxtop迈投(www.myfxtop.com)-靠谱的外汇跟单社区,免费跟随高手做交易!

 

免责声明:本文系转载自网络,如有侵犯,请联系我们立即删除,另:本文仅代表作者个人观点,与迈投财经(www.myfxtop.cn)无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。

著作权归作者所有。
商业转载请联系作者获得授权,非商业转载请注明出处。

風險提示

MyFxtops邁投所列信息僅供參考,不構成投資建議,也不代表任何形式的推薦或者誘導行為。MyFxtops邁投非外匯經紀商,不接觸妳的任何資金。 MYFXTOPS不保證客戶盈利,不承擔任何責任。從事外彙和差價合約等金融產品的槓桿交易具有高風險,損失有可能超過本金,請量力而行,入市前需充分了解潛在的風險。過去的交易成績並不代表以後的交易成績。依據各地區法律法規,MyFxtops邁投不向中國大陸、美國、加拿大、朝鮮居民提供服務。

邁投公眾號

聯繫我們

客服QQ:981617007
Email: service@myfxtop.com

MyFxtops 邁投