神经网络实验(第 1 部分):重温几何学
概述
在本文中,我想与大家分享我的神经网络实验。在阅读了 MQL5 上提供的大量信息后,我得出结论,就是理论知识足够了。 那里有许多好文章、函数库和源代码。 不幸的是,所有这些数据并不能得出一个合乎逻辑的结论 — 可盈利的一款交易系统。 我们试着解决这个问题。
我并非这个领域的专家,更不是作家或记者,但我会尝试以一种易于理解的方式表达我的思路,分享我的经验。
这些素材主要是为初学者设计的,比如我自己。
我的理解。 基础
一般来说,神经网络善于识别形态,而传递给神经网络进行训练的数据至关重要。 我将从这个假设开始。 我们要用到几何学。 我将把几何形状转换成神经网络。 首先,我们用一个常规的感知器,我在这里找到了它的样本(МTC Сombo - MetaTrader 4 的智能系统)。 在执行测试时,我决定放弃振荡器,转而采用均线。 测试若是涉及振荡器,则不会产生好结果。 我相信,当价格上升,振荡器下降时,每个人都知道所谓的背离。 均线参数更接近价格本身。
形状和线条
基准将由参数为 1 和 24、应用简单方法、收盘价的两条移动平均值指标组成。 换言之,其思路是不仅要传递当前指标位置,还要传递当前指标之前的状态。 在我看到的许多例子中,价格直接传递给神经网络,我认为这是根本错误的。
我以价值点的形式传递所有数值,这非常重要,因为这些数值有一个特定的范围,它们不能超出该范围。 将价格传递给神经网络是没有意义的,因为它可能在不同的范围内振荡,例如 10 年。 另外,请记住,在构建形状时,我们可用到不同数量的指标参数。 形状即可以很复杂,也可以很简单。 下面提供了一些可能的选项。 当然,您可以提出自己的方法。
已收盘蜡烛 1、4、7 和 10 距 MA 1 和 MA 24 之间的点数距离。
double perceptron1() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In2[1])/Point(); double a2 = (ind_In1[4]-ind_In2[4])/Point(); double a3 = (ind_In1[7]-ind_In2[7])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
形状 2:简单线条
已收盘蜡烛 1-4、4-7 和 7-10 距 MA1 之间的点数距离。
double perceptron2() { double w1 = y1 - 100.0; double w2 = y2 - 100.0; double w3 = y3 - 100.0; double a1 = (ind_In1[1]-ind_In1[4])/Point(); double a2 = (ind_In1[4]-ind_In1[7])/Point(); double a3 = (ind_In1[7]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3); }
形状 3:简单线条
已收盘蜡烛 1-4、4-7 和 7-10 距 MA 24 之间的点数距离。
double perceptron3() { double w1 = z1 - 100.0; double w2 = z2 - 100.0; double w3 = z3 - 100.0; double a1 = (ind_In2[1]-ind_In2[4])/Point(); double a2 = (ind_In2[4]-ind_In2[7])/Point(); double a3 = (ind_In2[7]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3); }
形状 4:蝴蝶(轨迹线)
已收盘蜡烛 1--10 距 MA 1 之间的点数距离。 以及已收盘蜡烛 1-10 距 MA 24 点数距离。蜡烛 1 的 MA 1 和 蜡烛 10 的 MA 24 之间的点数距离。 蜡烛1 的 MA 24 和蜡烛10 的 MA 1 之间的点数距离。 结果是一只蝴蝶。
double perceptron4() { double w1 = f1 - 100.0; double w2 = f2 - 100.0; double w3 = f3 - 100.0; double w4 = f4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/Point(); double a2 = (ind_In2[1]-ind_In2[10])/Point(); double a3 = (ind_In1[1]-ind_In2[10])/Point(); double a4 = (ind_In2[1]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
形状 5:四边形
已收盘蜡烛 1-1,10-10 距指标之间的点数距离。 以及 MA1 的 1-10 之间的点数距离,和指标 MA 24 的 1-10 之间的点数距离。 结果是一个四边形。
double perceptron5() { double w1 = c1 - 100.0; double w2 = c2 - 100.0; double w3 = c3 - 100.0; double w4 = c4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/Point(); double a2 = (ind_In2[1]-ind_In2[10])/Point(); double a3 = (ind_In1[1]-ind_In2[1])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
形状 6:复杂
在此,我将把上述所有形状组合成一个复杂的形状。
double perceptron6() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double w5 = y1 - 100.0; double w6 = y2 - 100.0; double w7 = y3 - 100.0; double w8 = z1 - 100.0; double w9 = z2 - 100.0; double w10 = z3 - 100.0; double w11 = f1 - 100.0; double w12 = f2 - 100.0; double w13 = f3 - 100.0; double w14 = f4 - 100.0; double a1 = (ind_In1[1]-ind_In2[1])/Point(); double a2 = (ind_In1[4]-ind_In2[4])/Point(); double a3 = (ind_In1[7]-ind_In2[7])/Point(); double a4 = (ind_In1[10]-ind_In2[10])/Point(); double a5 = (ind_In1[1]-ind_In1[4])/Point(); double a6 = (ind_In1[4]-ind_In1[7])/Point(); double a7 = (ind_In1[7]-ind_In1[10])/Point(); double a8 = (ind_In2[1]-ind_In2[4])/Point(); double a9 = (ind_In2[4]-ind_In2[7])/Point(); double a10 = (ind_In2[7]-ind_In2[10])/Point(); double a11 = (ind_In1[1]-ind_In1[10])/Point(); double a12 = (ind_In2[1]-ind_In2[10])/Point(); double a13 = (ind_In1[1]-ind_In2[10])/Point(); double a14 = (ind_In2[1]-ind_In1[10])/Point(); return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4 + w5 * a5 + w6 * a6 + w7 * a7 + w8 * a8 + w9 * a9 + w10 * a10 + w11 * a11 + w12 * a12 + w13 * a13 + w14 * a14); }
角度
我们来研究另一种将价格数据传递给感知器的有趣方法 — 指标倾角。 这些数据也不能超出某个范围,而这非常适合我们,因为我们希望传递某个模板,就像前面所用的形状和线条的情况一样。
我遇到了很多定义角度的方法,但其中很多都取决于价格图标的比例,这并不适合我。 所以我宁愿用点数与柱线的数量之比来计算切线角度,而非计算图表角度。 tg(α) 正切角度是相对支撑腿 a 与相邻支撑腿 b 的比率。
也可以使用不同指标数字,处理复杂结构,并用不同数量蜡烛进行分析。 坡度在屏幕截图上显示为非固定线。 我们来研究几个例子。
蜡烛 1-4、1-7 和 1-10 与 MA 1 之间的倾角。
double perceptront1() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double a1 = (ind_In1[1]-ind_In1[4])/4; double a2 = (ind_In1[1]-ind_In1[7])/7; double a3 = (ind_In1[1]-ind_In1[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3); }
蜡烛 1-4、和 1-10 与 MA 1 之间的倾角,蜡烛 1-5、和 1-10 与 MA 24 之间的倾角。
double perceptront2() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[5])/5; double a2 = (ind_In1[1]-ind_In1[10])/10; double a3 = (ind_In2[1]-ind_In2[5])/5; double a4 = (ind_In2[1]-ind_In2[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
感知器 3。 MA 1 和 MA 24 位置 4 坡度(以或多或少复杂的设计为例)
角度与 MA 1 和 MA 24 之间的斜率相关。
double perceptront3() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/10; double a2 = (ind_In2[1]-ind_In1[4])/4; double a3 = (ind_In2[1]-ind_In1[7])/7; double a4 = (ind_In2[1]-ind_In1[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
感知器 4。 MA 1 和 MA 24 位置 4 坡度(以或多或少复杂的设计为例)
角度与 MA 1 和 MA 24 之间的斜率相关。
double perceptront4() { double w1 = x1 - 100.0; double w2 = x2 - 100.0; double w3 = x3 - 100.0; double w4 = x4 - 100.0; double a1 = (ind_In1[1]-ind_In1[10])/10; double a2 = (ind_In2[1]-ind_In1[10])/10; double a3 = (ind_In1[1]-ind_In1[10])/10; double a4 = (ind_In2[1]-ind_In2[10])/10; return (w1 * a1 + w2 * a2 + w3 * a3 + w4 * a4); }
策略
我决定在下面的代码中明确指定,采用逆势趋势策略进行训练。 对于卖出,第一根蜡烛上的 MA 1 高于 MA 24。 买入的情况则相反。 这对于明确区分买卖是必要的。 另一方面,您可以做相反的事情 — 顺势而为。
您还可以用其她指标或其数值,例如 TEMA 指标。 在五位小数的品种上预测 400 点的价格走势是不可能的。 没有人知道行情将走向何方。 因此,为了进行测试,我为五位小数品种设置了 600 点的固定止损和 60 点的止盈。 您可以从下面下载现成的 EA。 我们看看结果。
//SELL++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1[1]>ind_In2[1]) && (perceptron1()<0) &&(SpreadS1<=MaxSpread)){//v1 OpenSell(symbolS1.Name(), LotsXSell, TakeProfit, StopLoss, EAComment); } //BUY++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1[1]<ind_In2[1]) && (perceptron1()>0) && (SpreadS1<=MaxSpread)){//v1 OpenBuy(symbolS1.Name(), LotsXBuy, TakeProfit, StopLoss, EAComment); }
优化、测试和资源
正如我们所知,神经网络的优化需要大量的计算资源。 因此,在利用策略测试器进行优化时,我建议采用“仅开盘价”模式,在代码中明确显示收盘价。 否则,即便以我相当有限的能力,也觉得这不是一项可行的任务。 但是,即使采用了这种优化模式,我也建议使用云网络服务。 优化的目标是找到某些可盈利的形态。 这种形态的发生率(可盈利的交易数量)应该远远高于无利可图形态。 这一切都取决于止损/获利比率。
往前看,我应该说我针对每个 EA 已经连续进行了 10 次优化。 会有很多优化值,这导致在遗传算法模式下每次通过的结果约为 10000-15000。 相应地,通过次数越多,找到所需权重比值的机会就越高。 该问题应通过 MQL5 手段解决。 我真的不想放弃策略测试。
与上面引用的文章(其中步骤等于 1)相比,5 步优化值不是偶然选择的。 在实验期间,我注意到这导致感知器权重比的结果更加分散,而这对结果有更佳的影响。
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (最大盈利)。
- 初始资金 10,000。
- 止盈 = 60,止损 = 600。
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
如您所见,结果距有希望甚远。 最佳结果为 0.87。 运行正向验证测试没有任何意义。
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (最大盈利)。
- 初始资金 10,000。
- 止盈 = 60,止损 = 600。
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
结果与之前的结果非常相似。最佳结果为 0.94。
优化 EA 4 感知器 4 图例。 (四个感知器四个不同形状)。
主要代码如下所示:
//SELL++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_SELL, EAComment)==0) && (ind_In1[1]>ind_In2[1]) && (perceptron1()<0) && (perceptron2()<0) && (perceptron3()<0) && (perceptron4()<0) && (SpreadS1<=MaxSpread)){//v1 OpenSell(symbolS1.Name(), LotsXSell, TakeProfit, StopLoss, EAComment); } //BUY++++++++++++++++++++++++++++++++++++++++++++++++ if ((CalculatePositions(symbolS1.Name(), Magic, POSITION_TYPE_BUY, EAComment)==0) && (ind_In1[1]<ind_In2[1]) && (perceptron1()>0) && (perceptron2()>0) && (perceptron3()>0) && (perceptron4()>0) && (SpreadS1<=MaxSpread)){//v1 OpenBuy(symbolS1.Name(), LotsXBuy, TakeProfit, StopLoss, EAComment); }
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (复杂准则最大化)。
- 初始资金 10,000。
- 止盈 = 200,止损 = 200。
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
前向验证测试日期从 2021 年 5 月 31 日至 2022 年 5 月 30 日。在所有结果中,我们应选择具有最大利润因子的结果,其中复杂标准的最大化值超过 40-50。
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (最大盈利)。
- 初始资金 10,000。
- 止盈 = 60,止损 = 600
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
得到了结果。最佳结果为 32。 把日期从 2021 年 5 月 31 日更改为 2022 年 5 月 30 日,并运行正向验证测试。 在所有结果中,我们应该选择利润因子最大、交易数量最小值不少于 10-20 的结果。
优化 EA 4 感知器 4 正切。 (四个感知器 四个不同的角度)。
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (复杂准则最大化)。
- 初始资金 10,000。
- 止盈 = 200,止损 = 200。
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
前向验证测试日期从 2021 年 5 月 31 日提前至 2022 年 5 月 30 日。 在所有结果当中,我们应该选择具有最大利润因子的一个,复杂准则的最大化值超过 20-40。
- 优化日期从 2010 年 5 月 31 日至 2021 年 5 月 30 日。
- 模式 (仅开盘价), (遗传算法), (最大盈利)。
- 初始资金 10,000。
- 止盈 = 60,止损 = 600。
- 周期 H1.
- 固定手数 0.01。
- 优化参数 x1, x2, x3, x4, y1, y2, y3, z1, z2, z3, f1, f2, f3, f4 - 感知器权重比。从 0 到 200,以 5 为增量进行优化。
优化和前向验证测试结果。
得到了结果。最佳结果为 32。 我会留下一个前向验证测试作为家庭作业。 我认为,这样会更有趣味。 此外,应当注意的是,与利润因子相关的交易数量有所增加。
在我的实验过程中,我遇到了几个需要解决的问题。
- 首先。 由于优化多个权重比参数的复杂性,有必要在 EA 代码中移动它们。
- 其二。 我们应该有一个包含所有优化参数的数据库,然后在 EA 中同时采用它们进行交易。 我认为,这可以用 .CSV 类型的文件。
结束语
我真的希望我的实验能给您带来新的发现,并最终取得成功。 我的目标是获得一个现成的盈利策略。 通过优良的前向验证测试结果,我已经部分达成了这一目标。 然而,还有许多工作要做。 现在是时候转向更复杂的系统,同时从掌握的经验中获益。 此外,我们应该更多地利用我们所拥有的。 我们会在实验的第二部分来讨论这个问题。 不要错过! 事情变得越发令人兴奋。
本文由MetaQuotes Ltd译自俄文
原文地址: https://www.mql5.com/ru/articles/11077