English Русский Español Deutsch 日本語 Português
preview
神经网络实验(第 2 部分):智能神经网络优化

神经网络实验(第 2 部分):智能神经网络优化

MetaTrader 5测试者 | 20 十月 2022, 09:39
1 660 0
Roman Poshtar
Roman Poshtar

概述

在上一篇文章神经网络实验(第 1 部分):重温几何学中,我分享了我与神经网络相关的观察和实验。 也就是说,我研究的是有关将哪种数据传递给神经网络的问题,并演示了一个涉及感知器的简单示例,从中得到可盈利的交易系统。 我在某些方面取得了成功,但也面临着一些困难,这些困难将在这里得到解决。 此外,我还打算迈入更复杂的神经网络。 为了达成此目的,我将运用来自文章利用 MQL 语言从头开始编程深度神经网络中的函数库。 该文作者非常详细地讲述了其工作原理,因此我只需关注主要层面。 本文的主要宗旨是开发一个基于神经网络的成熟交易机器人,立足 MetaTrader 5 且无需第三方软件。


基础和示例

上述函数库的作者用的是深度神经网络,但我建议从小处着手,构建一个具有 4-4-3 结构的网络。 总体来说,我们需要 (4 * 4)+ 4 +(4 * 3)+ 3 = 35 个权重和偏差值。

您可以在文后下载修改后的函数库文件。 我特意在代码中的所有更改处都保留了注释,以便您可以了解如何创建自定义神经网络。 

权重和偏差值:

input double w0=1.0;
input double w1=1.0;
input double w2=1.0;
input double w3=1.0;
input double w4=1.0;
input double w5=1.0;
input double w6=1.0;
input double w7=1.0;
input double w8=1.0;
input double w9=1.0;
input double w10=1.0;
input double w11=1.0;
input double w12=1.0;
input double w13=1.0;
input double w14=1.0;
input double w15=1.0;

input double b0=1.0;
input double b1=1.0;
input double b2=1.0;
input double b3=1.0;

input double x0=1.0;
input double x1=1.0;
input double x2=1.0;
input double x3=1.0;
input double x4=1.0;
input double x5=1.0;
input double x6=1.0;
input double x7=1.0;
input double x8=1.0;
input double x9=1.0;
input double x10=1.0;
input double x11=1.0;
input double x12=1.0;
input double x13=1.0;
input double x14=1.0;
input double x15=1.0;

input double s0=1.0;
input double s1=1.0;
input double s2=1.0;

W 和 X 是权重,B 和 S 是偏离参数。

包含神经网络库文件:

#include <DeepNeuralNetwork2.mqh> 

int numInput=4;
int numHiddenA = 4;
int numOutput=3;

DeepNeuralNetwork dnn(numInput,numHiddenA,numOutput);

接下来,我们将研究来自上一篇文章中的两个示例,即一个造型和一个具有倾角的形态。 我们也看一下函数库作者的策略结果。 最后,在不同的神经网络上检查所有这些 - 4-4-3 和 4-4-4-3。换句话说,我们一次性开发六个 EA。

传递蝴蝶 (轨道)。 图例 EA: 

r1


int error=CandlePatterns(ind_In1[1], ind_In1[10], ind_In2[1], ind_In2[10], _xValues);// Call the function

int CandlePatterns(double v1,double v2,double v3,double v4,double &xInputs[])// Function
  {

   xInputs[0] = (v1-v2)/Point();
   xInputs[1] = (v3-v4)/Point();
   xInputs[2] = (v1-v4)/Point();
   xInputs[3] = (v3-v2)/Point();
   
   return(1);

  }

传递带倾角形态(四条 MA 1 和 MA 24 指标倾角)。 倾角 EA:

r2


int error=CandlePatterns(ind_In1[1], ind_In1[5], ind_In1[10], ind_In2[1], ind_In2[5], ind_In2[10], _xValues);// Call the function

int CandlePatterns(double v1,double v2,double v3,double v4,double v5,double v6,double &xInputs[])// Function
  {

   xInputs[0] = (((v1-v2)/Point())/5);
   xInputs[1] = (((v1-v3)/Point())/10);
   xInputs[2] = (((v4-v5)/Point())/5);
   xInputs[3] = (((v4-v6)/Point())/50);
   
   return(1);

  }

经过策略测试器后,将权重和偏差的优化值设置为 -1 到 1,步长为 0.1。 得到 3.68597592780611e+51 次验算。 转到下一部分。

r3


解决优化问题

当运行上述 EA 时,策略测试器将在(慢速完整算法)模式下执行略高于 10,000 次的验算,在我们的例子中,该值太小而无法优化神经网络。 我认为,(快速遗传算法)模式在这里没有用处。

主要思路是只传递一个变量,就像某种排序计数器一样。 权重和偏差的其余参数将在 EA 内部设置。 出于这些目的,我决定尝试采用随机数生成器。 此外,有必要记住我们已经在优化中用到了哪些选项。

随机数生成器函数:

double RNDfromCI(double minp, double maxp) 
{ 
  if(minp == maxp) 
    return (minp); 
  double Minp, Maxp; 
  if(minp > maxp) 
  {
    Minp = maxp; 
    Maxp = minp;
  }
  else 
  {
    Minp = minp; 
    Maxp = maxp;
  }
  return (NormalizeDouble(double(Minp + ((Maxp - Minp) * (double)MathRand() / 32767.0)),1));
}

为了记住验算的参数,参考了几个选项。 特别是,EA 内部的数组不合适,因为它在每次 EA 初始化时都会被清零。 由于数据量太大,终端的全局变量也不适合。 还有必要在优化过程之外取得已完成的验算结果,并有可能读取数据。 故我决定使用 CSV 文件。

我们引入一个用于优化的变量:

input int Passages = 10000;

优化验算参数,从 1 至最大值,增量为 1。 在试运行基础上,找出一个变量模式下的最大验算次数。 其量级为 100,000,000。我想,这已足够了。

r4

最初,曾有一个想法是将 EA 分为两部分 — 其一个用于优化,其二用于交易。 但我认为,单一 EA 会更方便。 添加模式开关:

input bool Optimization = true;

主要的优化代码位于 EA 的 OnInit() 初始化函数当中:

if (Optimization==true){
int r=0;
int q=0;

 while(q!=1 && !IsStopped())
 {

string str;
 while(r!=1 && !IsStopped())
 {
   sw0=DoubleToString(RNDfromCI(Min, Max),1);
   sw1=DoubleToString(RNDfromCI(Min, Max),1);
   sw2=DoubleToString(RNDfromCI(Min, Max),1);
   sw3=DoubleToString(RNDfromCI(Min, Max),1);
   sw4=DoubleToString(RNDfromCI(Min, Max),1);
   sw5=DoubleToString(RNDfromCI(Min, Max),1);
   sw6=DoubleToString(RNDfromCI(Min, Max),1);
   sw7=DoubleToString(RNDfromCI(Min, Max),1);
   sw8=DoubleToString(RNDfromCI(Min, Max),1);
   sw9=DoubleToString(RNDfromCI(Min, Max),1);
   sw10=DoubleToString(RNDfromCI(Min, Max),1);
   sw11=DoubleToString(RNDfromCI(Min, Max),1);
   sw12=DoubleToString(RNDfromCI(Min, Max),1);
   sw13=DoubleToString(RNDfromCI(Min, Max),1);
   sw14=DoubleToString(RNDfromCI(Min, Max),1);
   sw15=DoubleToString(RNDfromCI(Min, Max),1);
   
   sb0=DoubleToString(RNDfromCI(Min, Max),1);
   sb1=DoubleToString(RNDfromCI(Min, Max),1);
   sb2=DoubleToString(RNDfromCI(Min, Max),1);
   sb3=DoubleToString(RNDfromCI(Min, Max),1);
   
   sx0=DoubleToString(RNDfromCI(Min, Max),1);
   sx1=DoubleToString(RNDfromCI(Min, Max),1);
   sx2=DoubleToString(RNDfromCI(Min, Max),1);
   sx3=DoubleToString(RNDfromCI(Min, Max),1);
   sx4=DoubleToString(RNDfromCI(Min, Max),1);
   sx5=DoubleToString(RNDfromCI(Min, Max),1);
   sx6=DoubleToString(RNDfromCI(Min, Max),1);
   sx7=DoubleToString(RNDfromCI(Min, Max),1);
   sx8=DoubleToString(RNDfromCI(Min, Max),1);
   sx9=DoubleToString(RNDfromCI(Min, Max),1);
   sx10=DoubleToString(RNDfromCI(Min, Max),1);
   sx11=DoubleToString(RNDfromCI(Min, Max),1);
   
   ss0=DoubleToString(RNDfromCI(Min, Max),1);
   ss1=DoubleToString(RNDfromCI(Min, Max),1);
   ss2=DoubleToString(RNDfromCI(Min, Max),1);
   
   if(StringFind(sw0,".", 0) == -1 ){sw0=sw0+".0";}
   if(StringFind(sw1,".", 0) == -1 ){sw1=sw1+".0";}
   if(StringFind(sw2,".", 0) == -1 ){sw2=sw2+".0";}
   if(StringFind(sw3,".", 0) == -1 ){sw3=sw3+".0";}
   if(StringFind(sw4,".", 0) == -1 ){sw4=sw4+".0";}
   if(StringFind(sw5,".", 0) == -1 ){sw5=sw5+".0";}
   if(StringFind(sw6,".", 0) == -1 ){sw6=sw6+".0";}
   if(StringFind(sw7,".", 0) == -1 ){sw7=sw7+".0";}
   if(StringFind(sw8,".", 0) == -1 ){sw8=sw8+".0";}
   if(StringFind(sw9,".", 0) == -1 ){sw9=sw9+".0";}
   if(StringFind(sw10,".", 0) == -1 ){sw10=sw10+".0";}
   if(StringFind(sw11,".", 0) == -1 ){sw11=sw11+".0";}
   if(StringFind(sw12,".", 0) == -1 ){sw12=sw12+".0";}
   if(StringFind(sw13,".", 0) == -1 ){sw13=sw13+".0";}
   if(StringFind(sw14,".", 0) == -1 ){sw14=sw14+".0";}
   if(StringFind(sw15,".", 0) == -1 ){sw15=sw15+".0";}

   if(StringFind(sb0,".", 0) == -1 ){sb0=sb0+".0";}
   if(StringFind(sb1,".", 0) == -1 ){sb1=sb1+".0";}
   if(StringFind(sb2,".", 0) == -1 ){sb2=sb2+".0";}
   if(StringFind(sb3,".", 0) == -1 ){sb3=sb3+".0";}
   
   if(StringFind(sx0,".", 0) == -1 ){sx0=sx0+".0";}
   if(StringFind(sx1,".", 0) == -1 ){sx1=sx1+".0";}
   if(StringFind(sx2,".", 0) == -1 ){sx2=sx2+".0";}
   if(StringFind(sx3,".", 0) == -1 ){sx3=sx3+".0";}
   if(StringFind(sx4,".", 0) == -1 ){sx4=sx4+".0";}
   if(StringFind(sx5,".", 0) == -1 ){sx5=sx5+".0";}
   if(StringFind(sx6,".", 0) == -1 ){sx6=sx6+".0";}
   if(StringFind(sx7,".", 0) == -1 ){sx7=sx7+".0";}
   if(StringFind(sx8,".", 0) == -1 ){sx8=sx8+".0";}
   if(StringFind(sx9,".", 0) == -1 ){sx9=sx9+".0";}
   if(StringFind(sx10,".", 0) == -1 ){sx10=sx10+".0";}
   if(StringFind(sx11,".", 0) == -1 ){sx11=sx11+".0";}
   
   if(StringFind(ss0,".", 0) == -1 ){ss0=ss0+".0";}
   if(StringFind(ss1,".", 0) == -1 ){ss1=ss1+".0";}
   if(StringFind(ss2,".", 0) == -1 ){ss2=ss2+".0";}
   
   str=sw0+","+sw1+","+sw2+","+sw3+","+sw4+","+sw5+","+sw6+","+sw7+","+sw8+","+sw9+","+sw10+","+sw11+","+sw12+","+sw13+","+sw14+","+sw15
   +","+sb0+","+sb1+","+sb2+","+sb3
   +","+sx0+","+sx1+","+sx2+","+sx3+","+sx4+","+sx5+","+sx6+","+sx7+","+sx8+","+sx9+","+sx10+","+sx11
   +","+ss0+","+ss1+","+ss2;
   if (VerifyPassagesInFile(str)==true)
   {
      ResetLastError();
      filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
      if(filehandle!=INVALID_HANDLE)
       {
        Print("FileOpen OK");
        FileSeek(filehandle, 0, SEEK_END);
        FileWrite(filehandle,Passages,sw0,sw1,sw2,sw3,sw4,sw5,sw6,sw7,sw8,sw9,sw10,sw11,sw12,sw13,sw14,sw15,
        sb0,sb1,sb2,sb3,
        sx0,sx1,sx2,sx3,sx4,sx5,sx6,sx7,sx8,sx9,sx10,sx11,
        ss0,ss1,ss2);
        FileClose(filehandle); 
        
   weight[0]=StringToDouble(sw0);
   weight[1]=StringToDouble(sw1);
   weight[2]=StringToDouble(sw2);
   weight[3]=StringToDouble(sw3);
   weight[4]=StringToDouble(sw4);
   weight[5]=StringToDouble(sw5);
   weight[6]=StringToDouble(sw6);
   weight[7]=StringToDouble(sw7);
   weight[8]=StringToDouble(sw8);
   weight[9]=StringToDouble(sw9);
   weight[10]=StringToDouble(sw10);
   weight[11]=StringToDouble(sw11);
   weight[12]=StringToDouble(sw12);
   weight[13]=StringToDouble(sw13);
   weight[14]=StringToDouble(sw14);
   weight[15]=StringToDouble(sw15);
   
   weight[16]=StringToDouble(sb0);
   weight[17]=StringToDouble(sb1);
   weight[18]=StringToDouble(sb2);
   weight[19]=StringToDouble(sb3);
   
   weight[20]=StringToDouble(sx0);
   weight[21]=StringToDouble(sx1);
   weight[22]=StringToDouble(sx2);
   weight[23]=StringToDouble(sx3);
   weight[24]=StringToDouble(sx4);
   weight[25]=StringToDouble(sx5);
   weight[26]=StringToDouble(sx6);
   weight[27]=StringToDouble(sx7);
   weight[28]=StringToDouble(sx8);
   weight[29]=StringToDouble(sx9);
   weight[30]=StringToDouble(sx10);
   weight[31]=StringToDouble(sx11);
   
   weight[32]=StringToDouble(ss0);
   weight[33]=StringToDouble(ss1);
   weight[34]=StringToDouble(ss2);
        
        r=1;
        q=1;
       }
      else 
       {
       Print("FileOpen ERROR, error ",GetLastError());
       q=0;
       }
   }
 }
 
 }
}

我解释一下代码。 教导 EA 等轮到它时去打开文件是一项令人兴奋的任务。 我遇到了在优化模式下同时打开同一个文件的问题,且同时用到多个 CPU 内核。 此问题已在第一个 “while” 循环中得到解决。 在打开文件进行写入之前,EA 不会退出 OnInit() 函数。 事实证明,EA 是在优化过程中逐个启动的。

当第一个内核进行测试时,EA 可以在第二个内核上打开一个文件写入。 进而,将最小值和最大值范围内的随机参数分配给所有权重和偏差。 如果数字已舍入,向其添加 .0。 将所有值添加到单个 “str” 字符串中。 调用 VerifyPassagesInFile(str) 函数检查字符串,查看文件中是否有相同的字符串。 如果没有,则将其写入文件末尾,并采用获得的权重和偏差的随机值填充 weight[] 数组。

检查参数的代码与先前函数相似:

bool VerifyPassagesInFile(string st){
string str="";
string str1="";
string str2="";
string str3="";
string str4="";
string str5="";
string str6="";
string str7="";
string str8="";
string str9="";
string str10="";
string str11="";
string str12="";
string str13="";
string str14="";
string str15="";
string str16="";
string str17="";
string str18="";
string str19="";
string str20="";
string str21="";
string str22="";
string str23="";
string str24="";
string str25="";
string str26="";
string str27="";
string str28="";
string str29="";
string str30="";
string str31="";
string str32="";
string str33="";
string str34="";
string str35="";
string str36="";

if (FileIsExist(OptimizationFileName)==
true ){
   ResetLastError();
   filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
   if(filehandle!=INVALID_HANDLE)
     {
      Print("FileCreate OK");
     }
   else Print("FileCreate ERROR, error ",GetLastError());
   FileClose(filehandle); 
}

   ResetLastError();
   filehandle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
   if(filehandle!=INVALID_HANDLE)
     {
      Print("FileOpen OK");
     }
   else Print("FileOpen ERROR, error ",GetLastError());
   
//--- read the data from the file
 while(!FileIsEnding(filehandle) && !IsStopped())
 {
  str1=FileReadString(filehandle);
  str2=FileReadString(filehandle);
  str3=FileReadString(filehandle);
  str4=FileReadString(filehandle);
  str5=FileReadString(filehandle);
  str6=FileReadString(filehandle);
  str7=FileReadString(filehandle);
  str8=FileReadString(filehandle);
  str9=FileReadString(filehandle);
  str10=FileReadString(filehandle);
  str11=FileReadString(filehandle);
  str12=FileReadString(filehandle);
  str13=FileReadString(filehandle);
  str14=FileReadString(filehandle);
  str15=FileReadString(filehandle);
  str16=FileReadString(filehandle);
  str17=FileReadString(filehandle);
  str18=FileReadString(filehandle);
  str19=FileReadString(filehandle);
  str20=FileReadString(filehandle);
  str21=FileReadString(filehandle);
  str22=FileReadString(filehandle);
  str23=FileReadString(filehandle);
  str24=FileReadString(filehandle);
  str25=FileReadString(filehandle);
  str26=FileReadString(filehandle);
  str27=FileReadString(filehandle);
  str28=FileReadString(filehandle);
  str29=FileReadString(filehandle);
  str30=FileReadString(filehandle);
  str31=FileReadString(filehandle);
  str32=FileReadString(filehandle);
  str33=FileReadString(filehandle);
  str34=FileReadString(filehandle);
  str35=FileReadString(filehandle);
  str36=FileReadString(filehandle);
    
    str=str2+","+str3+","+str4+","+str5+","+str6+","+str7+","+str8+","+str9+","+str10+","+str11
    +","+str12+","+str13+","+str14+","+str15+","+str16+","+str17+","+str18+","+str19+","+str20+","+str21
    +","+str22+","+str23+","+str24+","+str25+","+str26+","+str27+","+str28+","+str29+","+str30+","+str31+","+str32+","+str33+","+str34+","+str35+","+str36;
  if (str==st){FileClose(filehandle); return(false);}
 }

FileClose(filehandle); 
 
return(true); 
}

在此,我们首先检查文件 FileIsExist(OptimizationFileName) 是否存在。若无,则创建它。 接着,在 while(!FileIsEnding(filehandle) && !IsStopped()) 循环里读取字符串,保存到 str1- strN 变量之中。 将所有内容合并在一起到 “str” 变量当中。 将每个 “str” 字符串与函数输入处的传入 “st” 字符串进行比较。 最后,返回结果,无论是否存在匹配项。

生成的 EA 参数:

"------------Open settings----------------";

Optimization - 模式切换,优化或交易;

Min - 权重和偏差参数的最小值; 

Max - 权重和偏差参数的最大值; 

OptimizationFileName - 在优化期间写入参数,以及在交易模式下读取的文件名;

Passages - 验算值。 优化参数从 1 到 100,000,000 最大值,增量为 1;

LL - Softmax 函数提供基于 100% 总和的 3 个结果。 0.6 等于高于 60% 的值;

"------------Lots settings----------------";

SetFixLotOrPercent - 选择手数或资金百分比;

LotsOrPercent - 手数或百分比取决于 SetFixLotOrPercent;

"------------Other settings---------------";

MaxSpread - 开立订单的最大点差;

Slippage - 滑点;

Magic - 魔幻数字;

EAComment - 订单注释;

如您所知,默认情况下,MetaTrader 5 在其沙箱中创建文件。 

文件的路径:

C:\Users\您的用户名\AppData\Roaming\MetaQuotes\Terminal\Common\Files


优化

我们执行优化。 区间从 2018.07.12 至 2021.07.12。 EURUSD. H1, 开盘价。 测试运行次数: 10,000.

模式: (复杂判则最大值). Angle EA 4-4-3

a1

模式: (复杂判则最大值). Angle EA 4-4-4-3

a2

模式: (复杂判则最大值). 图例 EA 4-4-3

f1

模式: (复杂判则最大值). 图例 EA 4-4-4-3

f2

模式: (复杂判则最大值)。 Original EA 4-4-3. 函数库作者的策略。

o1

模式: (复杂判则最大值)。 Original EA 4-4-4-3. 函数库作者的策略。

o2

优化后(例如 10,000 次验算),我们能够启动新的优化,并继续把新参数填写到文件。 不要忘记事先保存策略测试器优化报告,和所需的验算参数。 我们还需要清除终端历史记录,否则测试程序会直接显示已完成的优化结果。 我用 .bat 类型脚本执行此操作。

del C:\Users\Your Username\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\cache\*.* /q /f /s

for /d %%i in (C:\Users\Your Username\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\cache\*) do rd /s /q "%%i"


del C:\Users\Your Username\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\logs\*.* /q /f /s

for /d %%i in (C:\Users\Your Username\AppData\Roaming\MetaQuotes\Terminal\36A64B8C79A6163D85E6173B54096685\Tester\logs\*) do rd /s /q "%%i"

取您自己电脑里的值替换 (Your Username) 和 (36A64B8C79A6163D85E6173B54096685)。 您可以利用常规文本编辑器打开它。 清理脚本附在下面。


使用优化结果

为了检查优化结果,请将 Optimization 开关设置为 “false”,并在验算参数中设置所需的验算索引。 为此,只需双击所要的结果即可。

加载测试权重和偏差参数的代码:

if (FileIsExist(OptimizationFileName)==false){
int id = 0;
int i = 0;
string f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f11,f12,f13,f14,f15,f16,f17,f18,f19,f20,f21,f22,f23,f24,f25,f26,f27,f28,f29,f30,f31,f32,f33,f34,f35,f36;
 int handle = FileOpen(OptimizationFileName,FILE_WRITE|FILE_READ|FILE_CSV|FILE_COMMON|FILE_ANSI, ";");
  if(handle!=INVALID_HANDLE)
   {Print("Loading optimization file.");
   
  while(!FileIsEnding(handle) && !IsStopped())
   {
   f1=FileReadString(handle);
   f2=FileReadString(handle);
   f3=FileReadString(handle);
   f4=FileReadString(handle);
   f5=FileReadString(handle);
   f6=FileReadString(handle);
   f7=FileReadString(handle);
   f8=FileReadString(handle);
   f9=FileReadString(handle);
   f10=FileReadString(handle);
   f11=FileReadString(handle);
   f12=FileReadString(handle);
   f13=FileReadString(handle);
   f14=FileReadString(handle);
   f15=FileReadString(handle);
   f16=FileReadString(handle);
   f17=FileReadString(handle);
   f18=FileReadString(handle);
   f19=FileReadString(handle);
   f20=FileReadString(handle);
   f21=FileReadString(handle);
   f22=FileReadString(handle);
   f23=FileReadString(handle);
   f24=FileReadString(handle);
   f25=FileReadString(handle);
   f26=FileReadString(handle);
   f27=FileReadString(handle);
   f28=FileReadString(handle);
   f29=FileReadString(handle);
   f30=FileReadString(handle);
   f31=FileReadString(handle);
   f32=FileReadString(handle);
   f33=FileReadString(handle);
   f34=FileReadString(handle);
   f35=FileReadString(handle);
   f36=FileReadString(handle);
 
   if (StringToInteger(f1)==Passages){
   weight[0]=StringToDouble(f2);
   Print(weight[0]);
   weight[1]=StringToDouble(f3);
   Print(weight[1]);
   weight[2]=StringToDouble(f4);
   Print(weight[2]);
   weight[3]=StringToDouble(f5);
   weight[4]=StringToDouble(f6);
   weight[5]=StringToDouble(f7);
   weight[6]=StringToDouble(f8);
   weight[7]=StringToDouble(f9);
   weight[8]=StringToDouble(f10);
   weight[9]=StringToDouble(f11);
   weight[10]=StringToDouble(f12);
   weight[11]=StringToDouble(f13);
   weight[12]=StringToDouble(f14);
   weight[13]=StringToDouble(f15);
   weight[14]=StringToDouble(f16);
   weight[15]=StringToDouble(f17);
   
   weight[16]=StringToDouble(f18);
   weight[17]=StringToDouble(f19);
   weight[18]=StringToDouble(f20);
   weight[19]=StringToDouble(f21);
   
   weight[20]=StringToDouble(f22);
   weight[21]=StringToDouble(f23);
   weight[22]=StringToDouble(f24);
   weight[23]=StringToDouble(f25);
   weight[24]=StringToDouble(f26);
   weight[25]=StringToDouble(f27);
   weight[26]=StringToDouble(f28);
   weight[27]=StringToDouble(f29);
   weight[28]=StringToDouble(f30);
   weight[29]=StringToDouble(f31);
   weight[30]=StringToDouble(f32);
   weight[31]=StringToDouble(f33);
   
   weight[32]=StringToDouble(f34);
   weight[33]=StringToDouble(f35);
   weight[34]=StringToDouble(f36);
   
   FileClose(handle);  
   break; 
   }
  
   }  
 FileClose(handle);
   }
   else{
   PrintFormat("Could not open file %s, error code = %d",OptimizationFileName,GetLastError());
   return(INIT_FAILED);
   }
}else{
   PrintFormat("Could not open file %s, error code = %d",OptimizationFileName,GetLastError());
   return(INIT_FAILED);
   }

Optimization 开关禁用时读取文件。 将第一列的值与 Passages 参数的值进行比较。 如果存在匹配项,将权重和偏差参数的值分配到我们的权重[]数组。 因此,我们可以测试最佳结果。

针对获得的结果进行前向验证测试,以便找到最好的三个。 在我的情况下,选择判则是最大盈利因子和交易数量超过 100:

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • Angle EA 4-4-3.

测试 1:

t1

测试 2:

t2

测试 3:

t3

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • Angle EA 4-4-4-3.

测试 1:

t4

测试 2:

t5

测试 3:

t6

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • 图例 EA 4-4-3.

测试 1:

t7

测试 2:

t8

测试 3:

t9

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • 图例 EA 4-4-4-3.

测试 1:

t10

测试 2:

t11

测试 3:

t12

接下来,在神经网络 4-4-3 和 4-4-4-3 中测试函数库作者的原始策略。

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • Original EA 4-4-3.

测试 1:

t13

测试 2:

t14

测试 3:

t15

  • 测试间隔: 从 2021.07.12 至 2022.07.12;
  • 模式: (基于真实跳价的每次跳价);
  • 初始资金: 10,000;
  • 时间帧: H1;
  • 固定手数 0.01;
  • Original EA 4-4-4-3.

测试 1:

t16

测试 2:

t17

测试 3:

t18

结果就是,Angle EA 4-4-3Angle EA 4-4-4-3 策略比之 图例 EA 4-4-3 和 图例 EA 4-4-4-3 工作得更加出色。 我认为,原因在于它们采用了非标准的方式进行市场分析。 优化过程基于 3 年内、2 个内核,大约需要 20 分钟。 此外,在实验之后,出现了许多需要解决的问题:

  1. 需要很长一段区间内执行优化。
  2. 增加验算数量。
  3. 决定前进的最佳策略。
  4. 开发一种算法,可同时处理某个交易优化结果的数据库。 我已经开始考虑这个问题了。 
  5. 开发同时优化和交易的算法。
  6. 采用不同的时间帧来查找最佳结果。
  7. 在一个 EA 中结合两个或多个神经网络,以及不同的数据集合。

    当然,完整的测试需要更深入的训练。 但取得的成果不言自明。 此外,这样的实验需要大量的计算资源。


    结束语

    在本文中,我们转向了更复杂的神经网络。 为了识别需传递给神经网络的必要数据,已经为此做了很多工作。 但可能并不会止步于此。 我们需要尝试从更多的指标传递数据,并使用复杂的链接。 我希望这将引导我们在开发可盈利交易机器人方面取得新的成功。 正如事实证明,MetaTrader 5 可以在没有第三方软件的情况下使用。 此外,我还开发了一个非常有趣的优化算法,它将扩展我们的能力。 

    像往常一样,我把进行更深入的优化和前向验证测试留给您来完成。

    附件:

    Angle EA 4-4-3 - МA1 和 МA24 指标倾角策略,神经网络 4-4-3。
    
    Angle EA 4-4-4-3 - МA1 和 МA24 指标倾角策略,神经网络 4-4-4-3。
    
    Figure EA 4-4-3 - МA1 和 МA24 指标蝴蝶(轨迹线)策略,神经网络 4-4-3。
    
    Figure EA 4-4-4-3 - МA1 和 МA24 指标蝴蝶(轨迹线)策略,神经网络 4-4-4-3。
    
    Original EA 4-4-3 - 蜡烛大小百分比策略,神经网络 4-4-3。
    
    Original EA 4-4-4-3 - 蜡烛大小百分比策略,神经网络 4-4-4-3。
    
    Clear.bat - 清理终端文件(Log 和 Cache).的脚本。
    
    DeepNeuralNetwork – 4-4-4-3 神经网络库。
    
    DeepNeuralNetwork2 – 4-4-3 神经网络库。
    


    本文由MetaQuotes Ltd译自俄文
    原文地址: https://www.mql5.com/ru/articles/11186

    附加的文件 |
    EA.zip (610.58 KB)
    学习如何基于标准偏差设计交易系统 学习如何基于标准偏差设计交易系统
    此为我们该系列中的一篇新文章,介绍如何利用 MetaTrader 5 交易平台中最受欢迎的技术指标来设计交易系统。 在这篇新文章中,我们将学习如何运用标准偏差指标设计交易系统。
    DoEasy. 控件 (第 11 部分): WinForms 对象 — 群组,CheckedListBox WinForms 对象 DoEasy. 控件 (第 11 部分): WinForms 对象 — 群组,CheckedListBox WinForms 对象
    本文将讨论 WinForms 对象群组,及创建 CheckBox 对象列表对象。
    神经网络变得轻松(第二十一部分):变分自动编码器(VAE) 神经网络变得轻松(第二十一部分):变分自动编码器(VAE)
    在上一篇文章中,我们已熟悉了自动编码器算法。 像其它任何算法一样,它也有其优点和缺点。 在其原始实现中,自动编码器会尽可能多地将对象与训练样本分开。 这次我们将讨论如何应对它的一些缺点。
    神经网络变得轻松(第二十部分):自动编码器 神经网络变得轻松(第二十部分):自动编码器
    我们继续研究无监督学习算法。 一些读者可能对最近发表的与神经网络主题的相关性有疑问。 在这篇新文章中,我们回到了对神经网络的研究。