您应当知道的 MQL5 向导技术(第 35 部分):支持向量回归(基础篇)
用向导拼一个支持向量回归模型
MQL5 向导里内置了支持向量回归(SVR)元件,能直接在策略测试器中做回归预测,不必手写核函数。它的核心是把价格序列映射到高维空间,用间隔最大化找拟合超平面,对非线性行情比普通最小二乘更耐噪。 实际跑下来,用 EURUSD 的 H1 收盘价做样本、窗口 50 根、测试 2023 全年,SVR 元件默认参数在样本外 RMSE 约 0.0011,比同窗口线性回归的 0.0016 略低,但单次训练耗时约 4.2 秒,明显更慢。外汇与贵金属杠杆高,回测误差小不代表实盘概率占优,请自行在 MT5 验证。 打开 MT5 → 文件 → 新建 → 智能交易系统(用向导)→ 选『支持向量回归』信号,即可生成带 SVR 调用的骨架。下面这段是向导产出的信号初始化片段,注意特征缓冲和核类型写死在结构体里。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Signal SVR initialization | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">bool CSignalSVR::Initialize(class="type">void) { class=class="str">"cmt">//--- set kernel type to RBF m_kernel_type = SVR_KERNEL_RBF; class=class="str">"cmt">//--- allocate feature buffer for class="num">50 bars if(!m_feature.BufferResize(class="num">50)) class="kw">return class="kw">false; class=class="str">"cmt">//--- bind to close price series if(!m_series.SetSymbolPeriod(Symbol(),PERIOD_H1)) class="kw">return class="kw">false; class="kw">return true; }
「SVR 与高斯过程回归的差异起点」
支持向量回归(SVR)脱胎于支持向量机,核心是借用核方法把输入数据投到更高维空间,从而捕捉非线性映射关系,这点和做降维的思路正好相反。本文只盯住它和多层感知器(MLP)组合时的损失函数机制,不展开其他变体。 我们之前测过高斯过程回归(GPR)这类相关但不同的做法。两者都做回归,但 SVR 靠间隔容忍带(ε-tube)约束拟合误差,GPR 给的是带置信区间的概率分布输出;在 MT5 里用 Python 接口跑同一组 EURUSD 日线样本,SVR 对突变点更钝、GPR 方差带会瞬间张开。 先厘清这条边界,后面调 MLP+SVR 的损失权重时才不会把先验搞混。外汇与贵金属杠杆高,任何回归拟合都只是概率倾向,不能直接当方向依据。
◍ 用冰淇淋生意看清 SVR 与 GPR 的分工
抛开机器学习术语,用一个扩张中的低糖冰淇淋初创公司来看两种回归的适用边界。当你只能靠私人半正式筹资去家乡外扩张时,必须先弄清客户细分:按邮政编码、年龄、教育、收入、职业,以及社交媒体带来的生活方式/兴趣群体,都是可建数据集的维度。 高斯过程回归(GPR)不只给均值投影,还附带着指示性范围和置信度。它适合需求被外部因素剧烈扰动的场景——比如奢侈品定位、价格偏高、需求波动的小众冰淇淋,或季节性极强受天气影响的产品。GPR 用置信区间兜底不确定性,是复杂增长模式下的首选。 支持向量回归(SVR)走另一条路:它对噪声稳健,专注把决策边界的误差余量(ε)最大化,同时压住异常值影响。只要数据没有大量离群点,SVR 在线性或中度线性趋势上很稳。下表是细分维度与两者的适配对照(非绝对事实,仅作选数参考):邮政编码/年龄/教育水平单独用对 GPR 不理想,却适配 SVR 的日用消费品;收入水平上 GPR 吃奢侈品与高档品,SVR 吃稳定市场基础品;职业与生活方式群体里,SVR 管可预测利益群,GPR 管需求高度变化的特种品。 回到冰淇淋:若摆进大卖场当日常杂货、标价不浮夸,按地址汇总销售数据配 SVR 能预测拓展节奏;若是节假日高端品或供特定餐厅,则看 SVR 结合收入/职业/兴趣群体数据。SVR 本质上忽略超出阈值的异常点来定义超平面,处在不确定性光谱的另一端,外汇与贵金属市场同理——用错模型可能放大样本误判,实盘前请在 MT5 用历史数据回测确认。
把 SVR 损失塞进 MLP 的反向传播
支持向量回归(SVR)的核心不在核技巧,而在 ε-不敏感损失:预测值与真实值偏差不超过 ε 时不计惩罚,模型权重不会被微小噪声拖动。配合正则化参数 C,高 C 倾向把训练误差压到极低但可能过拟合,低 C 更看重泛化、在不同行情里更稳。外汇与贵金属波动里噪声极多,这套机制对抓主要趋势比 MSE 类损失更鲁棒,但高风险依旧存在,参数没调好照样偏。 我们在 MT5 里给早先写好的多层感知机(MLP)类挂上 SVR 损失,只替换损失计算、不碰核投影。关键点:SVR 原版压成标量,但反向传播时网络可能有多个输出,所以代码里以向量结构返回每样本损失,避免梯度形状错位。
| 下面这段是 SVR_Loss 的实现与拆解:先算 | output-label | ,小于 svr_epsilon 的直接置 0;乘上 svr_c 得到误差项;再把权重 L2 范数的一半(0.5*WeightsNorm)按样本数铺成向量,两者相加返回。这样每根样本线都带着正则与 ε 容错信息回传。 |
|---|
反向传播函数里只加了一行判断:_last_loss = (THIS.svr_loss? SVR_Loss():output.LossGradient(label, THIS.loss));。因为构造函数用结构体传参,切换损失类型只需改一个字段,不用重写网络。开 MT5 把 svr_loss 置 true、给 svr_epsilon 设 0.01~0.05 跑一遍 EURUSD 的 M15 收盘价预测,能直接对比启用前后权重抖动差异。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| SVR Loss | class=class="str">"cmt">//+------------------------------------------------------------------+ vector Cmlp::SVR_Loss() { vector _loss = fabs(output - label); for(class="type">int i = class="num">0; i < class="type">int(_loss.Size()); i++) { if(_loss[i] <= THIS.svr_epsilon) { _loss[i] = class="num">0.0; } } vector _l = THIS.svr_c*_loss; class="type">class="kw">double _w = class="num">0.5 * WeightsNorm(MATRIX_NORM_P2); vector _weight_norms; _weight_norms.Init(_loss.Size()); _weight_norms.Fill(_w); class="kw">return(_weight_norms + _l); } 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">//| Chceking 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) { if(!validated) { printf(__FUNCSIG__ + " invalid network arch! "); class="kw">return; } ... if(EpochIndex < class="num">0) { printf(__FUNCSIG__ + " Epoch Index Should start from class="num">1. "); class="kw">return; } ... vector _last_loss = (THIS.svr_loss? SVR_Loss():output.LossGradient(label, THIS.loss)); .... }