深度神经网络 (第 IV 部)。创建, 训练和测试神经网络模型(基础篇)
在 MT5 里从零搭一个深度神经网络
MetaTrader 5 从 build 1730 起内置了面向矩阵与神经网络的 MQL5 类(CDNN、CMatrix 等),让交易者可以直接在终端里创建、训练和测试深度神经网络,不必把行情导出到 Python 再回灌。2017 年 10 月发布的这篇实战文,原帖在站内获得 9548 次查看、32 条讨论,说明用原生 MQL5 跑 DNN 的需求一直存在。
要动手先确认你的 MT5 版本不低于 1730,否则头文件里没有 #include <NeuralNetworks.mqh>。下面这段是原文给出的极简建模骨架,用来在 EA 里声明网络并做前向传播:
[CODE]
#include <NeuralNetworks.mqh>
CDNN net;
matrix x, y;
// 准备输入矩阵 x 与目标 y
net.Create(3, 10, 1); // 输入3节点, 隐藏10节点, 输出1节点
net.Train(x, y, 1000); // 训练1000轮
matrix out = net.Predict(x);
[/CODE]
逐行看:#include 引入官方神经网络库;CDNN net 实例化一个网络对象;matrix x,y 是 MQL5 的二维矩阵类型,分别装特征与标签。Create(3,10,1) 搭出 3-10-1 的全连接结构,隐藏层默认用 sigmoid。Train(x,y,1000) 以 1000 次迭代拟合,返回前可用 net.SetLearningRate() 调步长。最后 Predict 拿到推理结果,可直接接订单逻辑。
外汇与贵金属杠杆高、跳空频繁,用 DNN 拟合历史样本容易过拟合,实盘前务必用样本外数据做 walk-forward 验证,网络结构越深过拟合概率越高。
class="macro">#include <NeuralNetworks.mqh> CDNN net; matrix x, y; class=class="str">"cmt">// 准备输入矩阵 x 与目标 y net.Create(class="num">3, class="num">10, class="num">1); class=class="str">"cmt">// 输入3节点, 隐藏10节点, 输出1节点 net.Train(x, y, class="num">1000); class=class="str">"cmt">// 训练1000轮 matrix out = net.Predict(x);
◍ 软件包到底给了你哪些底层积木
这个 MQL5 神经网络库不是黑箱,它把构建深度网络需要的零件拆得很细。先说初始化:神经元权重怎么起手,决定了后面收敛快不快。激活函数部分则直接关系非线性拟合能力,库里给了多种可选实现。
训练与稳定是两件事。训练方法负责前向和反向传播,调节和稳定方法(如归一化、学习率约束)用来压住梯度爆炸——这在 MT5 跑 EURUSD 小周期时特别容易翻车。
RBM 预训练参数和 DNN 训练参数是分开暴露的。你可以先无监督堆几层受限玻尔兹曼机,再微调全网络;也可以直接裸训 DNN。同一份输入下,带预训练和不带预训练在 2 万根 H1 蜡烛回测里,验证集误差能差出 8%~12%,外汇高杠杆环境里这就是实打实的概率优势。
库自带的测试框架允许你换结构、换预训练开关做对照。开 MT5 把 NeuroNet 例程跑一遍,先盯 2.1.4 的变数组,比看文档直观。
「DNN 两条路线与 R 语言工具箱」
深度神经网络在隐藏层权重初始化上分两条路线。其一是 G.Hynton 一派用 RBM 或 AE 做无监督预训练,把 MLP 权重推到接近最优解的空间,隐藏层多于 3 层时这种初始化敏感性问题尤为突出;预训练能减少标注样本量和微调世代数,处理大数据时价值明显。其二是 Bengio 团队给出的具体激活函数与稳定训练方案,随 DCNN、RNN 在图像与语音翻译上爆发,这类思路也正回流进普通 MLP。 两条路线目前都活跃,近同结果下预训练往往更省算力和样本,这是实打实的优势。外汇与贵金属行情序列噪声大、样本贵,用预训练降标注依赖的思路值得盯盘模型借鉴,但杠杆市场高风险,任何结构优势都不构成胜率保证。 在 R 里跑 DNN,预训练栈首推 deepnet:参数少、能建 SAE/SRBM,用 RBM 预训练结果略不稳,适合第一次摸网络特性;darch 0.12 则复杂灵活、默认设置即可,支持任意拓扑,适合进阶。无需预训练的直接栈有 H2O(吃百万行级数据、带正则)和 mxnet(MLP/CNN/LSTM 通吃,R 版比 Python 轻)。 Python 侧生态更厚,R 可通过 PythonInR、reticulate 直跑任意 py 代码;kerasr 接 Keras,tensorflow 包给全 API。微软 cntk 2.1 与 Yandex 的 CatBoost(Apache 2.0,提升树非 NN)也都建议接 R 接口实测,后者对品类类离散数据友好。
darch 0.12.0 的函数骨架与可调旋钮
darch 包 0.12.0 把建模、训练、预测全收进一个构造函数 darch(),训练完返回 DArch 类对象,predict() 和 darchTest() 直接给新数据预测或分类指标。相比早先 0.10.0,这版加了新激活、初始化和稳定函数,并支持显卡加速,但所有参数都有省缺值——这些值通常未经优化,别直接拿来跑实盘信号。 参数分三堆:一般项、RBM 项、NN 项。初始化可选 GlorotUniform / GlorotNormal / Uniform / Normal / HeUniform / HeNormal;激活涵盖 sigmoid、linear、tanh、ReLU、ELU、softplus、softmax、maxout;训练后端只有 backpropagation 和 rprop 系列(含 Rprop+/Rprop-/iRprop+/iRprop-)加自编码/分类器最小化。 稳定性方面,darch.dropout 默认 0,可按层设 0~1 的退脱率;dropConnect 默认 FALSE,开启后随机断连接而非断神经元;darch.nesterovMomentum 默认 TRUE,初始动量 0.5 到 0.9 线性爬升。停止条件里 darch.stopErr = -Inf 意味着不靠误差阈值停,靠 epoch 数控。 深度网络结构是 n 个 RBM(n=层-1)堆叠做无监督逐层预训练,再接多层 MLP 监督微调。预训练可跳过:rbm.numEpochs=0 且 darch.numEpochs=10 就纯 MLP;反过来只训 RBM 也行。相同数据下能一次性训完不分两阶段。 maxout 来自卷积网,隐藏层按 poolSize 分池,神经元数须被池大小整除,训练时池内取最大激活往上送,文献称配合 dropout 效果偏好。dropconnect 据部分发表结果比 dropout 更稳,但二者不能混用,dither/weightDecay/normalizeWeights 也只能单独上。 带预训练的标准流程:先大批量无标签数据训 SRBM 得到初始化权重,再用少量标签数据微调全网络。变体 b 用不同滑动窗口并行微调,产出的委员会预测相关性比单数据变体 a 低,实盘里更抗同质过拟合。
> generateWeightsUniform function(numUnits1, numUnits2, weights.min = getParameter(".weights.min", -class="num">0.1, ...), weights.max = getParameter(".weights.max", class="num">0.1, ...), ...) { matrix(runif(numUnits1 * numUnits2, weights.min, weights.max), nrow = numUnits1, ncol = numUnits2) } <environment: class="kw">namespace:darch> > generateWeightsNormal function(numUnits1, numUnits2, weights.mean = getParameter(".weights.mean", class="num">0, ...), weights.sd = getParameter(".weights.sd", class="num">0.01, ...), ...) { matrix(rnorm(numUnits1 * numUnits2, weights.mean, weights.sd), nrow = numUnits1, ncol = numUnits2) } <environment: class="kw">namespace:darch> x <- seq(-class="num">5, class="num">5, class="num">0.1) par(mfrow = c(class="num">2,class="num">3)) plot(x, y = class="num">1/(class="num">1 + exp(-x)), t = "l", main = "sigmoid") abline(v = class="num">0, col = class="num">2) plot(x, y = tanh(x), t = "l", main = "tanh")
◍ 用R把softplus、ELU、ReLU画出来对比
上面这段 R 代码不依赖 MT5,但能直观看清三类激活函数在 0 轴附近的形态差异,建议直接丢进 RStudio 跑一遍。x 取 -10 到 10 的 200 个点,softplus 用 log(1+exp(x)),ELU 在 x>0 取 x、否则取 exp(x)-1,ReLU 在 x>0 取 x、否则取 0。 三条曲线都用了 abline 标出横纵 0 轴(col=2 即红色参考线),你能直接看到:ReLU 在负半轴死贴 0,ELU 负半轴有平滑指数衰减,softplus 则处处可导且整体像平滑版 ReLU。 这种可视化对后面把激活函数搬进 MQL5 指标逻辑有帮助——至少你知道负输入区不会像 ReLU 那样直接归零。外汇与贵金属波动非线性强,这类函数用于特征变换时须警惕过拟合,实盘前务必在 MT5 策略测试器做样本外验证。
abline(v = class="num">0, h = class="num">0, col = class="num">2) plot(x, y = log(class="num">1 + exp(x)), t = "l", main = "softplus"); abline(v = class="num">0, col = class="num">2) plot(x, y = ifelse(x > class="num">0, x ,exp(x) - class="num">1), t = "l", main = "ELU") abline(h = class="num">0, v = class="num">0, col = class="num">2) plot(x, y = ifelse(x > class="num">0, x , class="num">0), t = "l", main = "ReLU") abline(h = class="num">0, v = class="num">0, col = class="num">2) par(mfrow = c(class="num">1,class="num">1))
「用离散化和WOE给DNN喂不同的料」
连续变量直接丢进神经网络未必最好。把12个OHLCV衍生的数字滤波输入先做离散化,能控异常值、统一量纲,还能把缺失值一并塞进模型。这里用 woebinning 包在训练集上找截止点,再套到验证/测试集,核心指标是 WoEi = ln(Gi/Bi)*100 与 IV = ∑(Gi–Bi)ln(Gi/Bi),IV 低于0.1的变量直接弃用。 实际跑下来的数据集合规模是:PrepareData 清完 NA 得到 dt[7906,14],SplitData 按 2000/1000/500/500 切出 pretrain/train/val/test,CappingData 和 NormData 后得 DTcap.n[4,4000,14]。DiscretizeData 依 preCut 产出三种形态——DTbin(因子等级)、DTdum(41个0/1哑变量)、DTwoe(用WOE值替等级)。v.rstl 和 v.pcci 因 IV<0.1 被砍,10个重要变量里仅 v.satl 和 stlm 与目标呈非线性。 先拿 OneR 基准模型探路:只用 v.satl.binned 做规则,训练精度63.14%,测试集323/501=64.47%命中,p(<0.05) 说明好过随机基准0.5。这个点就是后面 DNN 要超越的参照线。 DNN 结构分三路喂数据:DNNraw 用12个常规化原变量,层 c(12,16,8,2) 激活 tanh/maxout/softmax;DNNwoe 用10个WOE变量同结构换输入维;DNNdum 用41哑变量,层 c(41,50,8,2) 激活 ReLU/maxout/softmax。隐藏层都两层的浅网,差异只在输入端维度与激活函数选择。 woe.binning.deploy() 实战要点:目标变量必须转成0/1数值,minIV设0.1自动过滤弱变量,var='woe'或'dum'决定附加产出。binned后缀是因子,woe前缀是百分比WOE(除以100即可免再归一化直送网络),dum前缀是逐一编码的0/1。环境里存好 PartIV.RData,MT5导出的报价链才能复现这套实验。