神经网络在交易中的实际应用·进阶篇
「把指标计算丢给训练好的网络」
做一套用到十几个指标、多周期多时间窗口的 EA,实盘跑起来很容易把终端算力吃满,回测也难收敛。一个务实做法是:先用这些指标的历史值训练神经网络,之后 EA 只负责把相对价格数据喂给网络模块,由它输出 0/1 信号再做决策。 以随机振荡器为例,用裸价格数据当输入、指标本身当训练样本,训完后的网络输出在图上能复现标准指标的级别、交叉、反转和背离特征——整个过程没写任何复杂公式。 作者用 NeuroSolutions 和 Matlab 生成独立可执行模块,再挂进 MT4/MT5 的 EA 框架:MT4 模块读价格文件 Input_mat,吐出 Open1/2/3 信号文件。复杂系统搭好后,改参数和试错成本很低,准备数据、训练 Net1 和 Net2 并跑通首轮优化大约只需 10 分钟。 外汇与贵金属杠杆高、滑点跳空频繁,神经网络的 0/1 输出只是概率倾向,实盘前务必用历史数据交叉验证。下方代码是导价格特征进训练文件的片段,注意它偏移了 4、3、2 三根 K 线来构造时序样本。
<span class="functions">FileWrite</span>(handle, <span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>)-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>)-<span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>)-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">4</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="functions">iHighest</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="macro">MODE_HIGH</span>,<span class="number">class="num">5</span>,i+<span class="number">class="num">4</span>))-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="functions">iLowest</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="macro">MODE_LOW</span>,<span class="number">class="num">5</span>,i+<span class="number">class="num">4</span>)), <span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>)-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>)-<span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>)-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">3</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="functions">iHighest</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="macro">MODE_HIGH</span>,<span class="number">class="num">5</span>,i+<span class="number">class="num">3</span>))-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="functions">iLowest</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,<span class="macro">MODE_LOW</span>,<span class="number">class="num">5</span>,i+<span class="number">class="num">3</span>)), <span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">2</span>)-<span class="functions">iLow</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">2</span>), <span class="functions">iHigh</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">2</span>)-<span class="functions">iClose</span>(<span class="macro">NULL</span>,<span class="number">class="num">0</span>,i+<span class="number">class="num">2</span>)
用 iHigh/iLow 拼出三周期波动特征
这段片段在给特征向量按偏移量 i、i+1、i+2 三组 K 线填值,每组都同时算实体上下段与影线全幅,外加 5 根窗口内的最高最低差。注意 i+2 组只给了两根线:单根振幅和 5 根极值差,比 i+1、i 两组少了收盘减最低、最高减收盘两项,说明远端样本权重被刻意压薄。 iHighest 与 iLowest 的第三个参数固定为 5,回看窗口从各自偏移位起算,所以 i+2 的极值区实际覆盖的是 [i+2, i+6]。若当前图表周期跳到 M1,这套 5 根窗口约对应 5 分钟波动,换 H1 则放大到 5 小时,跨周期直接改观特征尺度。 最后一行 iStochastic 用了 (5,3,3) 慢随机、主线、shift=i,再拼上 iTime(NULL,60,i) 的小时级时间戳。把这段直接贴进 MT5 的 OnTick 前的数组填充处,开 EURUSD 观察 i 从 0 走到 200 时特征维度是否对齐,外汇与贵金属杠杆高,回测结论仅代表历史概率倾向。
iHigh(NULL,class="num">0,i+class="num">2)-iLow(NULL,class="num">0,i+class="num">2), iHigh(NULL,class="num">0,iHighest(NULL,class="num">0,MODE_HIGH,class="num">5,i+class="num">2))-iLow(NULL,class="num">0,iLowest(NULL,class="num">0,MODE_LOW,class="num">5,i+class="num">2)), iClose(NULL,class="num">0,i+class="num">1)-iLow(NULL,class="num">0,i+class="num">1), iHigh(NULL,class="num">0,i+class="num">1)-iClose(NULL,class="num">0,i+class="num">1), iHigh(NULL,class="num">0,i+class="num">1)-iLow(NULL,class="num">0,i+class="num">1), iHigh(NULL,class="num">0,iHighest(NULL,class="num">0,MODE_HIGH,class="num">5,i+class="num">1))-iLow(NULL,class="num">0,iLowest(NULL,class="num">0,MODE_LOW,class="num">5,i+class="num">1)), iClose(NULL,class="num">0,i)-iLow(NULL,class="num">0,i), iHigh(NULL,class="num">0,i)-iClose(NULL,class="num">0,i), iHigh(NULL,class="num">0,i)-iLow(NULL,class="num">0,i), iHigh(NULL,class="num">0,iHighest(NULL,class="num">0,MODE_HIGH,class="num">5,i))-iLow(NULL,class="num">0,iLowest(NULL,class="num">0,MODE_LOW,class="num">5,i)), iStochastic(NULL,class="num">0,class="num">5,class="num">3,class="num">3,MODE_SMA,class="num">1,MODE_MAIN,i), TimeToStr(iTime(NULL,class="num">60,i))
◍ 用文件桥接让 MT5 与神经网络对话
把神经网络塞进 MT5 不需要复杂 IPC,最稳的办法是让终端和 NN 程序通过磁盘文件互传数据。终端每次只写几十个字节的最小化特征,NN 侧读完后把信号回写文件,延迟虽发生在下一 tick 信号到达之后,但只要系统不炒超短线就无伤大雅。本文系统只吃开盘价,因此对这种异步节奏不敏感。 这种文件桥接的关键收益是可逐步三重测试:每一阶段收发的字节都可控,能把程序逻辑错误概率压到最低。代价是 NN 程序里要按 EA 用途(测试或实盘)硬编码文件路径。下图涉及的 Input_mat、Bar 由 EA 生成,Open1/2/3 由 NN 生成;Bar 只是个计数器辅助文件。 Open1/2/3 的第一行放前一次响应、第二行放实时响应,这种两行结构是因三个网络用不同间隔训练而定的特殊格式,响应文件个数和布局会随交易条件变化。外汇与贵金属杠杆高、滑点突变频繁,实盘前务必在「每次即时报价」和「按检查点」两种模式都跑一遍,传统 EA 在逐 tick 下翻车是常事,NN 系统两种模式结果应接近才可信。
「三层验证把神经网络接进实盘」
搭基于神经网络的交易系统,不能只靠训练集好看。我实际跑通的流程分三个测试阶段,每一层都在堵「训练好用、实盘失灵」的洞。 第一层是快速测试:用脚本或 EA 把「训练截止后到当前」的历史段写成文件,丢进 Matlab 取 NN 响应,再转成指标。这个指标融合了 12 种自定义指标派生出的 52 个特征,标准终端指标也能塞进去。用它直接优化进出场,不花大时间就能看系统骨架靠不靠谱。 第二层回 Matlab 原生环境:用神经网络工具箱重训、用命令窗口取响应,生成第二个指标。理论上它该和第一层的指标一致;若策略回测结果对不上,说明数据管道或特征工程有断点,得回去查。 第三层是交叉控制点测试。MT5/MT4 里跑 EA,同时 Matlab 跑系统 NN 模块脚本,在任意间隔取控制点信号。若这次信号和前次同间隔结果重合,方向就对了;再把 NN 模块编译、挂 UI 测一遍,结果仍相似,才谈得上拿真实账户跑——外汇和贵金属杠杆高,模型过拟合会在极端波动里放大亏损,实盘前务必留样本外验证。
训练样本怎么切分决定信号形态
神经网络的响应长什么样,基本由你喂了哪段行情样本决定。同一套输入特征,换一批训练样本就能长出不同的指标曲线,进而派生出不同的交易逻辑;把几套不同样本训出来的模型叠用,最终结果的波动往往比单模型更平缓。 前面章节用过按交易周期极端点挑样本的做法,这里再给一个具体变体:我训了两个网络,一个专看买入、一个专看卖出。训练规则是——价格已经触到阶段最低但还没触到最高时归一类,反过来触到最高还没触到最低时归另一类。 这两个指标各自是对 12 个自定义指标的压缩诠释。图上红线高点表示触底后的网络输出,灰色高点对应触顶位置。它们可以分开优化,也能组合测试,比如看两线交叉、算两者差值、或者测某条水平线的穿越。 要注意,单独优化 12 个原始指标本身已经很吃算力,样本切分不当会让调参空间直接爆炸。外汇与贵金属杠杆高、滑点跳空频繁,这类多模型组合策略务必先在 MT5 历史中心做样本外回测再上实盘。
◍ 收束
市面讲神经网络交易的文章不少,但落到 MT4/MT5 实盘怎么接、怎么跑的真东西稀缺,多数材料默认你已懂 MQL 或 MATLAB。作者那本俄语第二版把 MetaTrader 4 接 MATLAB 的逐步流程写透了,想照做可直接找来对着改。 外汇与贵金属自带高杠杆高风险,神经网络信号只是概率倾向,别把回测顺滑当成实盘保本。开 MT5 把文里的模块拆开验证,比单纯收藏帖子更有用。