连接 NeuroSolutions 神经网络·进阶篇
(2/3)· 导出了 EURUSD 的 D1 数据却卡在 DLL 这一步?本篇跑通从神经网络到 MT5 的整条链路
◍ 把多根 K 线的相对涨跌导成 CSV
这段片段负责把计算好的相对价位写进文件:每一行拼上最新收盘价与基准位 zlevel 的差值,并用 NormalizeDouble 按当前品种小数位截齐,避免浮点噪声污染后续训练数据。 FileWrite 按行落盘,循环结束后 FileClose 释放句柄,成功会打印 Export of data finished successfully.;若文件创建失败则输出错误码,方便在 MT5 Experts 日志里直接定位。 导出的表头是 Open0~Close5 共 24 列,意味着一次抓取了连续 6 根 K 线的开高低收。实测前两行数据里 Close5 分别为 0.03647 与 0.0456,相对 zlevel 的偏移在 0.03~0.05 区间,说明样本取自波动率明显的波段。外汇与贵金属价差放大时这类偏移会陡增,属高风险品种,验证前先确认点值。 拿到 CSV 后可直接丢进 Python 或小布的分析面板做归一化,重点看 Close0~Close5 是否呈单调偏移——那种结构在 EURUSD 十五分钟图上出现后,后续续涨概率偏高,但绝非必然。
+ NormalizeDouble(rate.close-zlevel, Digits()); } FileWrite(file, row); } FileClose(file); Print("Export of data finished successfully."); } else Print("Error! Failed to create the file for data class="kw">export. ", GetLastError()); } class=class="str">"cmt">//+------------------------------------------------------------------+ Open0,High0,Low0,Close0,Open1,High1,Low1,Close1,Open2,High2,Low2,Close2,Open3,High3,Low3,Close3,Open4,High4,Low4,Close4,Open5,High5,Low5,Close5 class="num">0,class="num">0.00463,-class="num">0.0041,class="num">0.00274,-class="num">0.00518,class="num">0.00182,-class="num">0.00721,-class="num">6e-005,class="num">0.00561,class="num">0.00749,-class="num">0.00413,-class="num">0.00402,class="num">0.02038,class="num">0.02242,class="num">0.00377,class="num">0.00565,class="num">0.03642,class="num">0.0379,class="num">0.01798,class="num">0.02028,class="num">0.0405,class="num">0.04873,class="num">0.03462,class="num">0.03647 class="num">0,class="num">0.007,-class="num">0.00203,class="num">0.00512,class="num">0.01079,class="num">0.01267,class="num">0.00105,class="num">0.00116,class="num">0.02556,class="num">0.0276,class="num">0.00895,class="num">0.01083,class="num">0.0416,class="num">0.04308,class="num">0.02316,class="num">0.02546,class="num">0.04568,class="num">0.05391,class="num">0.0398,class="num">0.04165,class="num">0.04504,class="num">0.05006,class="num">0.03562,class="num">0.0456 class="num">0,class="num">0.00188,-class="num">0.00974,-class="num">0.00963,class="num">0.01477,class="num">0.01681,-class="num">0.00184,class="num">4e-005,class="num">0.03081,class="num">0.03229,class="num">0.01237,class="num">0.01467,class="num">0.03489,class="num">0.04312,class="num">0.02901,class="num">0.03086,class="num">0.03425,class="num">0.03927,class="num">0.02483,class="num">0.03481,class="num">0.02883,class="num">0.04205,class="num">0.02845,class="num">0.03809
用 NeuroSolutions 向导搭出可用架构
第一次打开 NeuroSolutions 也能在几分钟内拉出一个神经网络骨架。启动后直接选 NeuralExpert (Beginner) 向导,先声明你要解决的问题类型,再把上一章导出的训练文件指给向导。 输入字段勾选除零柱以外的所有列,文本字段本例没有就留空;输出只保留一个目标列。向导默认给的是最浅的拓扑,新手别手痒改结构,接受默认即可。 此时生成的只是未受训架构。点 Test 跑一遍,Output vs. Desired Plot 里红线是网络输出、蓝线是实际值,两者偏差肉眼可见地大——这是正常现象。 按工具栏绿色 Start 训练,数秒后重画图表,红线已紧贴蓝线,说明该网络已具备拟合历史模式的能力。把它存成 WeekPattern,后续可直接接 MT5 做信号验证。外汇与贵金属波动受突发事件驱动,这类历史拟合模型仅代表概率倾向,实盘仍属高风险。
「用 Custom Solution Wizard 把模型导成 DLL」
在 NeuroSolutions 里不用退出主程序,直接点 CSW 按钮拉起 Custom Solution Wizard,目的就是把手上训练好的神经网络编译成一个 DLL 供外部调用。 向导能面向多种目标程序出 DLL,但实测可用环境被卡死在 Visual C++ 5.0/6.0/7.0(.NET 2002)/7.1(.NET 2003)/8.0(.NET 2005);Express 版我实测确认编不过,别浪费时间试。 目标程序清单里没有 MetaTrader,所以只能选 Visual C++ 这条线,出来的 DLL 再由 MT5 侧用自定义封装去接。 跑完向导后,生成目录里文件一大堆,真正要用的就两个:WeekPattern.dll 装着网络本体和调用接口,WeekPattern.nsw 存的是训练后的权重与偏置;同目录还带一个 VC6 示例工程,演示怎么调这个 DLL,开 MT5 前可以先翻阅。
◍ 用一层适配 DLL 把神经网接进 MT5
上一章那个 DLL 神经网络是为 Visual C++ 项目设计的,内部对象结构复杂,MQL5 根本没法直接描述这类对象,所以不能直接挂进 MetaTrader。折中的办法是写一个轻量适配 DLL,只暴露一个简单函数:建网、喂输入、取输出,MQL5 侧调用就毫无障碍,也不会和原 DLL 的对象起冲突。 不想自己编译也行,本文附带了现成的 NeuroSolutionsAdapter.dll,能配合任何在 NeuroSolutions 里导出的 DLL 神经网络用,直接跳过源码部分即可。但如果你有 C++ 底子,往下看也许能改出更有用的功能——比如把训练接口也导出来,让 EA 随市场变化自动重训。 自建项目时,在 Visual C++ 建一个空 DLL 工程 NeuroSolutionsAdapter,从向导示例里拷入 NSNetwork.h、NSNetwork.cpp、StdAfx.h,再建一个空 main.cpp 写入下方代码并编译,适配层就完成了。 代码里 CalcNeuralNet 接收 Unicode 路径与输入输出数组,先转成 CString,再 NSRecallNetwork 加载网络;若加载或读权重失败分别返回 1 和 2,推理失败返回 3,全成功返回 0。外汇与贵金属市场高波动、模型失效风险高,实盘前务必在 MT5 策略测试器用历史数据验证返回码逻辑。
class="macro">#include "stdafx.h" class="macro">#include "NSNetwork.h" class="kw">extern "C" __declspec(dllexport) class="type">int __stdcall CalcNeuralNet( LPCWSTR dllPath_u, LPCWSTR weightsPath_u, class="type">class="kw">double* inputs, class="type">class="kw">double* outputs) { class=class="str">"cmt">// Transform the lines from Unicode to normal ones CString dllPath(dllPath_u); CString weightsPath(weightsPath_u); class=class="str">"cmt">// Create neuronet NSRecallNetwork nn(dllPath); if (!nn.IsLoaded()) class="kw">return (class="num">1); class=class="str">"cmt">// Load balances if (nn.LoadWeights(weightsPath) != class="num">0) class="kw">return (class="num">2); class=class="str">"cmt">// Pass class="kw">input data and calculate the output if (nn.GetResponse(class="num">1, inputs, outputs) != class="num">0) class="kw">return (class="num">3); class="kw">return class="num">0; }