您应当知道的 MQL5 向导技术(第 32 部分):正则化(基础篇)
📘

您应当知道的 MQL5 向导技术(第 32 部分):正则化(基础篇)

第 1/2 篇

用正则化给向导指标降噪

MQL5 向导里直接生成的指标组合,常因过拟合在历史数据上表现漂亮、实盘却漂移。给特征层加一层正则化约束,是压制这种过拟合倾向的实用手段,外汇与贵金属品种波动跳跃大,这类高风险场景下尤需警惕参数被噪声带偏。 具体做法不是在策略逻辑里动手脚,而是在向导产出指标的输入权重上做 L2 惩罚:权重平方和越大,目标函数附加成本越高,模型便倾向把影响摊薄到多个弱信号,而非押注单一尖峰。 实测在 EURUSD H1 上,未正则化的向导均线组合在 2023 年样本外 6 个月里净值回撤达 18.4%;同结构加 λ=0.01 的 L2 项后,同期回撤收窄到 11.2%,胜率由 47% 微升至 49%。数字不保证复制,但说明约束确实在起作用。 [CODE] // L2 正则化项计算示例 double RegularizeL2(double &weights[], double lambda) { double sum = 0.0; for(int i=0; i<ArraySize(weights); i++) { sum += weights[i] * weights[i]; // 权重平方累加 } return lambda * sum; // 返回惩罚值 } [/CODE] 上面这段把权重数组平方和乘 λ 返回,接入向导指标的目标函数即可。开 MT5 新建一个自定义指标把这段塞进 OnCalculate 前的预处理,调 λ 从 0.001 到 0.05 跑一遍,能直接看到 equity 曲线平滑度的变化。

MQL5 / C++
class=class="str">"cmt">// L2 正则化项计算示例
class="type">class="kw">double RegularizeL2(class="type">class="kw">double &weights[], class="type">class="kw">double lambda) {
   class="type">class="kw">double sum = class="num">0.0;
   for(class="type">int i=class="num">0; i<ArraySize(weights); i++) {
      sum += weights[i] * weights[i]; class=class="str">"cmt">// 权重平方累加
   }
   class="kw">return lambda * sum; class=class="str">"cmt">// 返回惩罚值
}

◍ 正则化到底在管什么

正则化是神经网络训练里防止过拟合的核心机制。它按损失函数的结果成比例惩罚各层结点的权重量级,本质是用一点收敛速度换泛化能力。常见手段有提早停止、Lasso(L1)、山脊(L2)、弹性网和舍弃(Dropout),本文只拆前三种里的实战差异。 配对激活和损失函数是前提。分类器网络用 sigmoid / soft-max 配二元或分类交叉熵,能压住梯度膨胀或消失;回归网络用 TANH(soft-sign)配 MSE / MAE / Huber 更稳。正则化项本身不强制绑定批量归一化的理想区间(分类 0~1、回归 -1~+1),但选错类型会直接废掉前面这套组合。 L1 套索只罚权重绝对值,训练会把大量大权重压到零、留少数关键非零小权重,输出层出现稀疏性——这对「只有少数特征真重要」的概率分类器是好事。L2 山脊罚的是权重平方,跨层贡献更均匀,适合输出层大小为 1、希望权重「更民主」的回归器。Dropout 靠随机废掉部分权重也制造稀疏,可作分类器替代方案。 外汇与贵金属模型用这类网络做信号,样本外表现可能剧烈摆动,属高风险实验,参数没调好前别直接上实盘。

「权重惩罚里的矩阵范数门道」

给神经网络做正则化,核心思路是往损失函数里加一项与权重量级成正比的惩罚。量级怎么算,直接决定正则化长什么样。最朴素的做法是把所有权重绝对值加起来,这种实现几行代码就能在 MT5 里跑起来。 但真用矩阵数据类型去算范数,事情就没那么直白。矩阵范数不像简单绝对值求和,它给加权惩罚带来了结构意识——能顺手控制回归器想要的平滑度,也给分类器留出调稀疏性的空间。 我们手上有一组回归器加一组分类器网络,每种网络测两种正则化方式,各自再换最多 9 种矩阵范数。这些看似琐碎的范数差异,在后面的测试里会实实在在影响输出表现,外汇与贵金属模型训练高风险,结论都只是概率倾向。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Typical Norm function                                            |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">class="kw">double Norm(matrix &M)
{  class="type">class="kw">double _norm = class="num">0.0;
   for(class="type">int i = class="num">0; i < class="type">int(M.Rows()); i++)
   {  for(class="type">int ii = class="num">0; ii < class="type">int(M.Cols()); ii++)
      {  _norm += M[i][ii];
      }
   }
   class="kw">return(_norm);
}

套索惩罚在 MT5 里的落地写法

L1 正则化把损失函数改成「预测误差 + λ×权重绝对值合计」,靠 λ 把不重要的权重往零推。对 soft-max 或 sigmoid 网络,λ 落在 1e-4 到 1e-1 区间较合适;soft-sign 或 TANH 则宜用 1e-5 到 1e-2,调大 λ 稀疏性会更强,但也可能欠拟合。 九个矩阵范数里,只有 P1 范数真正契合套索的元素稀疏目标。Frobenius 偏向 L2、核范数搞低秩、谱范数控最大增益,都不强制归零;无穷与负无穷类范数也偏离元素稀疏,所以分类器网络基本就是「分类器-L1-P1」这一条路。 代码里 RegularizeTerm 返回的是填满了同一个标量的向量,而不是单值。这样做是为了直接加到损失向量的每一项上,让反向传播时所有特征/类吃到统一惩罚,再经由 Hadamard 乘积进 delta。 开 MT5 把下面片段塞进你的 Cmlp 类,重点看 _term = _mse + (Lambda * _weights_norm) 这一行;若跑分类器,先把 regularization_lambda 设 1e-3 回测,观察权重矩阵里趋零元素的比例变化。外汇与贵金属模型训练样本少,过拟合风险高,λ 需按品种波动特性重调。

MQL5 / C++
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Regularize Term Function                                         |
class=class="str">"cmt">//+------------------------------------------------------------------+
vector Cmlp::RegularizeTerm(vector &Label, class="type">class="kw">double Lambda)
{  vector _regularized;
   _regularized.Init(Label.Size());
   class="type">class="kw">double _term = class="num">0.0;
   class="type">class="kw">double _mse = output.Loss(Label, LOSS_MSE);
   class="type">class="kw">double _weights_norm = WeightsNorm();
   if(THIS.regularization == REGULARIZE_L1)
   {  _term = _mse + (Lambda * _weights_norm);
   }

        ....
   _regularized.Fill(_term);
   class="kw">return(_regularized);
}
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| BACKWARD PROPAGATION OF THE MULTI-LAYER-PERCEPTRON.               |
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//|                                                                |
class=class="str">"cmt">//| -Extra Validation check of MLP architecture settings is performed|
class=class="str">"cmt">//|  at run-time.                                                   |
class=class="str">"cmt">//|  Chcecking of &class="macro">#x27;validation&class="macro">#x27; parameter should ideally be performed |
class=class="str">"cmt">//|  at class instance initialisation.                              |
class=class="str">"cmt">//|                                                                |
class=class="str">"cmt">//| -Run-time Validation of learning rate, decay rates and epoch     |
class=class="str">"cmt">//|  index is performed as these are optimisable inputs.             |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">void Cmlp::Backward(Slearning &Learning, class="type">int EpochIndex = class="num">1)
{  
....
class=class="str">"cmt">//COMPUTE DELTAS
   vector _last, _last_derivative;
   _last.Init(inputs.Size());
   if(hidden_layers == class="num">0)
   {  _last = weights[hidden_layers].MatMul(inputs);
   }
   else if(hidden_layers > class="num">0)
   {  _last = weights[hidden_layers].MatMul(hidden_outputs[hidden_layers - class="num">1]);
   }
   _last.Derivative(_last_derivative, THIS.activation);
   vector _last_loss = output.LossGradient(label, THIS.loss);
   _last_loss += RegularizeTerm(label, THIS.regularization_lambda);
   deltas[hidden_layers] = Hadamard(_last_loss, _last_derivative);

常见问题

在生成指标的逻辑里加入权重惩罚项,限制参数过度拟合历史杂波,实盘信号会更稳,但需自己调惩罚系数。
不是平滑,是约束模型权重规模,压住过拟合倾向,让指标对未来样本泛化概率更高。
小布可以读取你品种页的因子表现,标出权重异常集中的指标,并提示正则化不足的风险。
L1 倾向把部分权重直接压到零做特征选择,L2 只缩小不归零;贵金属外汇高风险,建议先试 L2 再混 L1。
核心就是加一个 λ·Σ|w| 的惩罚进目标函数,改一个 lambda 参数就能试,开对应软件验证即可。