用直线函数摸清神经网络的正向传播
◍ 用直线函数摸清神经网络的正向传播
在 MT5 里跑通第一个神经网络,不一定要上复杂结构。先拿最简单的直线函数 y = w*x + b 做正向传播,就能看清权重和偏置怎么作用到输入上。 我们在 EA 的 OnTick 里写一段前向计算,把外部传入的 x、w、b 乘加后得到预测 y。这套逻辑是后续多层网络的基础,改一个参数就能观察输出偏移。 下面这段代码在 MT5 编译后可直接用于观察:给 w=2.0、b=1.0、x=3.0,预期 y=7.0,实际输出应与手算一致。外汇与贵金属行情受杠杆影响,回测仅验证计算逻辑,实盘仍属高风险。
class="type">class="kw">double w = class="num">2.0, b = class="num">1.0, x = class="num">3.0; class="type">class="kw">double y = w * x + b; Print("y = ", y);
「先跳过数学,直接看能跑的代码」
上篇《神经网络实践:最小二乘法》只用单一变量拟合了一条最能描述数据集的简单方程,本篇不重复推导过程。背后的闭式解涉及大量分析数学与代数运算,若真想啃计算细节,建议从博弈论切入——它能以更有趣的形式让你熟悉推导,而不必陷在无止境的算式复习里。 如果你只想在 MT5 里验证效果,本篇不会展开统计与概率的解释,数学部分留待深究者处理。我们会冷静地给出若干能从数据库生成描述函数的办法,重点放在可执行的 MQL5 实现上,而不是理论证明。 对外汇与贵金属交易者而言,任何基于历史数据拟合的函数都只是概率描述,实盘应用属高风险行为,参数漂移可能导致信号失效。
用最小二乘在 MT5 里拟合任意截距直线
上一节只解决了截距 b=0 的直线拟合,现实数据库里的点往往不穿过原点。把最小二乘从「过原点」推广到一般式 y = a·x + b,核心是多算一个 b 的偏导,同时用数据库里的点求 a 和 b 两个常数,而不是只猜斜率。 代码里矩阵 A 存了 4 组整数坐标:(-100,-150)、(-80,-50)、(30,80)、(100,120),共 k=4 个点。第 46 行把 err、dx、dy、dxy、dx2 全初始化为 0,第 47 行 k 置 0,准备累加。 第 52~55 行分别累加 Σx、Σy、Σxy、Σx²,这些都是代入公式的前置量。第 62 行用 (k·Σxy - Σx·Σy) / (k·Σx² - (Σx)²) 算斜率 a,第 63 行用 (Σy - a·Σx) / k 算截距 b。把这套式子直接译成 MQL5,比手算快且不易错。 程序第 66 行把算出的方程画到画布上,跑出来 a 约 1.06、b 约 -36,和肉眼理想线有偏差但很接近。想更准就改 step 参数:示例用 0.1,调更小(如 0.01)精度更高但耗时更长,没有百分百完美解,只有误差与速度的平衡点。 若你的贵金属或外汇样本点明显弯曲,这条直线模型会失效;此时要换二次多项式并重写常数求解,外汇/贵金属数据波动大、过拟合风险高,验证前先小批量回测。
class="num">28. class=class="str">"cmt">//+------------------------------------------------------------------+ class="num">29. class="type">void Func_01(class="type">void) class="num">30. { class="num">31. class="type">int A[]={ class="num">32. -class="num">100, -class="num">150, class="num">33. -class="num">80, -class="num">50, class="num">34. class="num">30, class="num">80, class="num">35. class="num">100, class="num">120 class="num">36. }; class="num">37. class="num">38. class="type">int vx, vy; class="num">39. class="type">uint k; class="num">40. class="type">class="kw">double ly, err, dx, dy, dxy, dx2, a, b; class="num">41. class="type">class="kw">string s0 = ""; class="num">42. class="num">43. canvas.LineVertical(global.x, global.y - _SizeLine, global.y + _SizeLine, ColorToARGB(clrRoyalBlue, class="num">255)); class="num">44. canvas.LineHorizontal(global.x - _SizeLine, global.x + _SizeLine, global.y, ColorToARGB(clrRoyalBlue, class="num">255)); class="num">45. class="num">46. err = dx = dy = dxy = dx2 = class="num">0; class="num">47. k = class="num">0;
◍ 回归线与残差在画布上的逐点落地
这段循环把数组 A 里的坐标对逐个取出,一边累加最小二乘所需的各项和,一边在 MT5 画布上直接画出红点和紫色残差垂线。vx、vy 分别取自 A 的连续两格,dx、dy、dxy、dx2 同步累加,第 56 行用半径 5 像素的红点标记原始散点,第 59 行从点到回归线的纵向偏差画一条紫线,视觉上能立刻看出哪几个点偏离主轴最远。 第 57 行的 ly 计算把点投影到按 global.Angle 旋转后的坐标系,再减掉 global.Const_B 得到残差纵距;第 58 行用 %.4f 精度把绝对值拼进字符串 s0,第 60 行把 ly 平方累加到 err。跑完循环后,第 62–63 行用 k 个样本点算出斜率 a 与截距 b:a=((k*dxy)-(dx*dy))/((k*dx2)-dx^2),b=(dy-a*dx)/k,这就是拟合出的 f(x)=ax+b。 最后三行 PlotText 把总误差(%.8f 精度)、逐点残差串、以及拟合方程直接绘到图表。外汇与贵金属价格序列用这套拟合时,样本窗口一换,a/b 可能剧烈跳动,属高波动品种常见现象,参数 step 默认 0.1 仅用于角度微调函数,不改变回归本身。
for (class="type">uint c0 = class="num">0, c1 = class="num">0; c1 < A.Size(); c0++, k++) { vx = A[c1++]; vy = A[c1++]; dx += vx; dy += vy; dxy += (vx * vy); dx2 += MathPow(vx, class="num">2); canvas.FillCircle(global.x + vx, global.y - vy, class="num">5, ColorToARGB(clrRed, class="num">255)); ly = vy - (vx * -MathTan(_ToRadians(global.Angle))) - global.Const_B; s0 += StringFormat("%.4f || ", MathAbs(ly)); canvas.LineVertical(global.x + vx, global.y - vy, global.y + (class="type">int)(ly - vy), ColorToARGB(clrPurple)); err += MathPow(ly, class="num">2); } a = ((k * dxy) - (dx * dy)) / ((k * dx2) - MathPow(dx, class="num">2)); b = (dy - (a * dx)) / k; PlotText(class="num">3, StringFormat("Error: %.8f", err)); PlotText(class="num">4, s0); PlotText(class="num">5, StringFormat("f(x) = %.4fx %c %.4f", a, (b < class="num">0 ? &class="macro">#x27;-&class="macro">#x27; : &class="macro">#x27;+&class="macro">#x27;), MathAbs(b))); } class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void NewAngle(const class="type">char direct, const class="type">char updow, const class="type">class="kw">double step = class="num">0.1)
「用伪逆把散点压成一条直线」
把标量写法换成矩阵,并不是炫技。变量一多,逐个写时间序列会把自己绕死;矩阵因式分解让角系数 a 和截距 b 直接躺在同一个向量 q 里,省掉一堆中间变量。 上面那套推导最后收敛到摩尔-彭罗斯伪逆:转置矩阵求逆再乘 y 向量,一次给出斜率和交点。原文作者半开玩笑说该拿诺奖,但实用价值是真的——SCILab、MATLAB、Excel 都能跑,MT5 里也能自己写。 下面这段 SCILab 代码就是最小可运行样本:x 取 [-100,-80,30,100],y 取 [-150,-50,80,120],红点是原始位置,蓝线是伪逆拟合的直线。你开 SCILab 粘贴就能看到图;想验证 MT5 侧一致性,把同样四个点喂进你自己的线性回归块即可。 伪逆的有趣之处在于矩阵 A 可以换列:加 x^2、x^3 就能拟合高阶多项式,不用改框架,只动 ones(x) 那一侧的构造。外汇和贵金属波动高危,这种拟合只描述历史点分布,对未来拐点是概率性参考,不是方向保证。
clc; clear; clf; x=[-class="num">100; -class="num">80; class="num">30; class="num">100]; y=[-class="num">150; -class="num">50; class="num">80; class="num">120]; A = [ones(x), x]; plot(x, y, &class="macro">#x27;ro&class="macro">#x27;); zoom_rect([-class="num">150, -class="num">180, class="num">180, class="num">180]); xgrid; x = pinv(A) * y; b = x(class="num">1); a = x(class="num">2); x =[-class="num">120:class="num">1:class="num">120]; y = a * x + b; plot(x, y, &class="macro">#x27;b-&class="macro">#x27;);
把工具请下神坛
伪逆分解依赖矩阵运算,手动推两三个常数还算轻松,但写进 MQL5 就得处理维度泛化和数值稳定性,不能只抄某篇特定例程。本文附的 Anexo_01.mq5 仅 4.88 KB,说明通用求解器本身不长,难的是你真读懂它在算什么。 外汇与贵金属杠杆高、滑点跳空频繁,任何数学拟合都只是概率辅助,别把伪逆出来的 a、b 当圣杯。 真要落地,就把压缩包里脚本拖进 MT5 跑一遍,改两行输入看输出怎么变,比反复读文有用。工具就是工具,摸过才知道边界在哪。