神经网络实践:伪逆(I)(基础篇)
📘

神经网络实践:伪逆(I)(基础篇)

第 1/2 篇

◍ 用伪逆给 MT5 神经网络求权重

在 MT5 里搭一个极简单层线性网络,核心其实就一步:拿输入矩阵 X 直接算伪逆,乘上目标 Y,得到权重 W。比起梯度下降,这种方法没有迭代、不调学习率,适合样本量不大、想快速验证映射关系的场景。 MQL5 没有内建伪逆函数,得自己用奇异值分解(SVD)思路写。下面这段把矩阵转置、乘自身、求逆再左乘的链路摊开,跑一遍就能在策略测试器里看到 W 被算出来。外汇与贵金属波动有跳空和杠杆风险,伪逆拟合只是数学近似,实盘信号概率会随样本外数据衰减。 [CODE] // 计算伪逆:pinv(X) = inv(X^T * X) * X^T double pinvMatrix[][N], XtX[][N], Xt[][M]; MatrixTranspose(X, Xt); // X 转置存入 Xt MatrixMultiply(Xt, X, XtX); // Xt 乘 X 得 XtX MatrixInverse(XtX, XtX); // 对 XtX 求逆(满秩前提) MatrixMultiply(XtX, Xt, pinvMatrix); // 逆阵左乘 Xt 得伪逆 [/CODE] 代码里 N 是特征数、M 是样本数,MatrixInverse 在行列式接近 0 时会失败,所以喂数据前最好做列归一。小布盯盘里接这段,可以把历史收盘价差做输入,下一根 K 线方向做 Y,先跑 200 根观察拟合误差。

MQL5 / C++
class=class="str">"cmt">// 计算伪逆:pinv(X) = inv(X^T * X) * X^T
class="type">class="kw">double pinvMatrix[][N], XtX[][N], Xt[][M];
MatrixTranspose(X, Xt);          class=class="str">"cmt">// X 转置存入 Xt
MatrixMultiply(Xt, X, XtX);      class=class="str">"cmt">// Xt 乘 X 得 XtX
MatrixInverse(XtX, XtX);         class=class="str">"cmt">// 对 XtX 求逆(满秩前提)
MatrixMultiply(XtX, Xt, pinvMatrix); class=class="str">"cmt">// 逆阵左乘 Xt 得伪逆

「先泼冷水:纯 MQL5 手搓伪逆不是捷径」

很多人以为套几个现成库就能几天内训出能稳定刷外汇曲线的神经网络,这想法本身就危险。外汇和贵金属是高杠杆品种,哪怕最简单的单层感知机,从矩阵分解到伪逆求解,每一步都可能因为数值误差把信号带偏,实盘里亏的就是保证金。 前面三篇 AI 文章已经铺垫过:神经网络是被研究了几十年的硬骨头,不是「低代码拖拽」能绕开的。本文不打算给你造幻觉——只靠浅知识绝无可能做出真正能赚钱的交易模型;谁这么承诺,基本是在骗。 今天我们用纯 MQL5 数组手搓伪逆,不用系统自带的 matrix::PInv,也不走 MQL5 原生矩阵类。原因很简单:数组在内存里的元素寻址逻辑和矩阵类略有差异,自己写一遍才能看清分解过程每一步在算什么。代码刻意写得啰嗦、不追求执行效率,教育意义优先。初学者看不懂别急,逐行跟。 顺带一个数据点:MQL5 标准库里 PInv 函数早已存在,本文重造轮子不是为了性能,而是为了把黑盒拆开——你开 MT5 新建脚本把下面代码贴进去,跑通一次比看十篇科普都实在。

先用标准库伪逆给自己打根基

在 MT5 里验证伪逆,最省事的办法是直接调 MQL5 标准库的 PInv 方法。先跑通官方实现,拿到基线结果,后面自己手写的分解逻辑才有对照物——这是避免「信仰式编程」的第一步。 下面这段就是最小可运行样例:建一个 4 行 2 列的矩阵,直接 Print 出它的 Moore–Penrose 逆。控制台里能看到原矩阵和逆矩阵并排打印,结构非常直白。 [CODE] 里的第 06 行定义了 M_A,四组 (1, x) 数据常用于线性回归的偏置项构造;第 11 行 M_A.PInv() 一句话完成伪逆,底层走的是标准库的数值分解。 别急着改代码。原文强调过,在拿原始版本跑出结果前动任何参数,都可能得到和参考实现对不上的输出,那样你根本分不清是算法错了还是输入错了。外汇与贵金属相关的矩阵拟合场景波动大、高风险,先确认基线再谈优化。 等你对标准库输出心里有数了,再去看伪逆内部怎么用矩阵乘法和极小阈值归零来拆——那时候改代码才叫「摸过、看过、信过」。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class="macro">#class="kw">property copyright "Daniel Jose"
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void OnStart()
{
    matrix M_A {{class="num">1, -class="num">100}, {class="num">1, -class="num">80}, {class="num">1, class="num">30}, {class="num">1, class="num">100}};

    Print("Moore–Penrose inverse of :");
    Print(M_A);
    Print("is :");
    Print(M_A.PInv());
}
class=class="str">"cmt">//+------------------------------------------------------------------+

◍ 伪逆计算的矩阵乘法与行列式拆解

伪逆在数值上就是「转置乘原矩阵 → 求逆 → 再乘转置」三步,但 MQL5 里每一步都得自己写底层过程。先说通用矩阵乘法:下面的 Generic_Matrix_A_x_B 不依赖任何外部库,靠传入的行列数在运行时推算维度,能对任意二维 flat 数组做乘算。 第 2 行声明过程,A 为左矩阵、B 为右矩阵、R 为结果,A_Row 是 A 的行数,B_Line 是 B 的列数,R_Row 回传结果行数。第 4–5 行用 A.Size()/A_Row 反推 A 的列数,用 B.Size()/B_Line 反推 B 的行数——这就是通用化的核心。 第 7 行检查 A_Row != B_Line,矩阵乘要求左列数等于右行数,否则第 9 行打印报错,第 10 行用 1/MathAbs(0) 故意触发除零让终端崩掉,防止后续算出错误矩阵。第 12 行测 R 是否为动态数组,静态数组在第 14 行同样抛错退出。 别把正态当圣经:MQL5 动态内存不会自动清零,第 18 行要手动清掉 R 的分配区,否则旧指标缓冲数据可能混进计算,这在贵金属回测里会悄悄扭曲伪逆结果。 行列式用 Sarrus 法最直白:1x1 直接返回自身,2x2 走特判,更大方阵用宏扫主副对角线。示例里红色 3x3 矩阵算出来行列式是 79,蓝色区只是元素副本辅助理解。外汇与贵金属杠杆高、滑点随机,这类线性代数模块只在历史数据验证时有意义,实盘信号概率仍受流动性干扰。

MQL5 / C++
<span class="number">class="num">01</span>. <span class="comment">class=class="str">"cmt">//+------------------------------------------------------------------+</span>
<span class="number">class="num">02</span>. <span class="keyword">class="type">void</span> Generic_Matrix_A_x_B(<span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> &amp;A[], <span class="keyword">const</span> <span class="keyword">class="type">uint</span> A_Row, <span class="keyword">const</span> <span class="keyword">class="type">class="kw">double</span> &amp;B[], <span class="keyword">const</span> <span class="keyword">class="type">uint</span> B_Line, <span class="keyword">class="type">class="kw">double</span> &amp;R[], <span class="keyword">class="type">uint</span> &amp;R_Row)
<span class="number">class="num">03</span>. {
<span class="number">class="num">04</span>.&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">class="type">uint</span> A_Line = (<span class="keyword">class="type">uint</span>)(A.Size() / A_Row),
<span class="number">class="num">05</span>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;B_Row&nbsp;&nbsp;= (<span class="keyword">class="type">uint</span>)(B.Size() / B_Line);
<span class="number">class="num">06</span>.
<span class="number">class="num">07</span>.&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">if</span> (A_Row != B_Line)
<span class="number">class="num">08</span>.&nbsp;&nbsp;&nbsp;&nbsp; {
<span class="number">class="num">09</span>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Operation cannot be performed because the number of rows is different from that of columns..."</span>);
<span class="number">class="num">10</span>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; B_Row = (<span class="keyword">class="type">uint</span>)(<span class="number">class="num">1</span> / <span class="functions">MathAbs</span>(<span class="number">class="num">0</span>));
<span class="number">class="num">11</span>.&nbsp;&nbsp;&nbsp;&nbsp; }
<span class="number">class="num">12</span>.&nbsp;&nbsp;&nbsp;&nbsp; <span class="keyword">if</span> (!<span class="functions">ArrayIsDynamic</span>(R))
<span class="number">class="num">13</span>.&nbsp;&nbsp;&nbsp;&nbsp; {
<span class="number">class="num">14</span>.&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span class="functions">Print</span>(<span class="class="type">class="kw">string">"Response array must be of the dynamic type..."</span>);

常见问题

手动实现矩阵求逆和乘法步骤多,浮点累积误差会让权重偏离,先用标准库验证思路更稳。
不能。外汇贵金属高风险,伪逆只是拟合历史,信号可能失效,务必先模拟验证。
可以。小布盯盘的 AIGC 已内置这类诊断,打开对应品种页就能看到信号概率与偏离提示。
行列式趋零代表矩阵近奇异,除法放大噪声,权重数值会剧增,需加正则或丢弃该样本。
先搞清矩阵乘法维度对齐和行列式含义,否则代码跑通也读不懂权重代表什么。