
神经网络实验(第 2 部分):智能神经网络优化
概述
在上一篇文章神经网络实验(第 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:
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:
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 次验算。 转到下一部分。
解决优化问题
当运行上述 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。我想,这已足够了。
最初,曾有一个想法是将 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
模式: (复杂判则最大值). Angle EA 4-4-4-3
模式: (复杂判则最大值). 图例 EA 4-4-3
模式: (复杂判则最大值). 图例 EA 4-4-4-3
模式: (复杂判则最大值)。 Original EA 4-4-3. 函数库作者的策略。
模式: (复杂判则最大值)。 Original EA 4-4-4-3. 函数库作者的策略。
优化后(例如 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:
测试 2:
测试 3:
- 测试间隔: 从 2021.07.12 至 2022.07.12;
- 模式: (基于真实跳价的每次跳价);
- 初始资金: 10,000;
- 时间帧: H1;
- 固定手数 0.01;
- Angle EA 4-4-4-3.
测试 1:
测试 2:
测试 3:
- 测试间隔: 从 2021.07.12 至 2022.07.12;
- 模式: (基于真实跳价的每次跳价);
- 初始资金: 10,000;
- 时间帧: H1;
- 固定手数 0.01;
- 图例 EA 4-4-3.
测试 1:
测试 2:
测试 3:
- 测试间隔: 从 2021.07.12 至 2022.07.12;
- 模式: (基于真实跳价的每次跳价);
- 初始资金: 10,000;
- 时间帧: H1;
- 固定手数 0.01;
- 图例 EA 4-4-4-3.
测试 1:
测试 2:
测试 3:
接下来,在神经网络 4-4-3 和 4-4-4-3 中测试函数库作者的原始策略。
- 测试间隔: 从 2021.07.12 至 2022.07.12;
- 模式: (基于真实跳价的每次跳价);
- 初始资金: 10,000;
- 时间帧: H1;
- 固定手数 0.01;
- Original EA 4-4-3.
测试 1:
测试 2:
测试 3:
- 测试间隔: 从 2021.07.12 至 2022.07.12;
- 模式: (基于真实跳价的每次跳价);
- 初始资金: 10,000;
- 时间帧: H1;
- 固定手数 0.01;
- Original EA 4-4-4-3.
测试 1:
测试 2:
测试 3:
结果就是,Angle EA 4-4-3 和 Angle EA 4-4-4-3 策略比之 图例 EA 4-4-3 和 图例 EA 4-4-4-3 工作得更加出色。 我认为,原因在于它们采用了非标准的方式进行市场分析。 优化过程基于 3 年内、2 个内核,大约需要 20 分钟。 此外,在实验之后,出现了许多需要解决的问题:
- 需要很长一段区间内执行优化。
- 增加验算数量。
- 决定前进的最佳策略。
- 开发一种算法,可同时处理某个交易优化结果的数据库。 我已经开始考虑这个问题了。
- 开发同时优化和交易的算法。
- 采用不同的时间帧来查找最佳结果。
- 在一个 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


