在算法交易中 Kohonen 神经网络的实际应用。 第 I 部分 工具·综合运用
(3/3)· 前两层铺垫完概念与工具,这一层把网络真正接进 EA 与行情预测闭环
很多交易者把 Kohonen 网络当成优化结果的可视化摆设,靠肉眼从拓扑图里找参数,判断标准飘忽不定。本文收尾篇直接把网络接进自动决策:修掉索引与归一化旧坑,跑通测试、预测与参数优选。前面两篇没解决的“自动提取知识”,在这里闭环。
搭一个 SOM-Explorer 把网络跑起来
把 Kohonen 网络从纸面放到 MT5 里,最直接的方式是写一个通用 EA,命名为 SOM-Explorer,把封装好的 CSOM 类头文件包含进来,用输入参数控制网络结构与可视化。EA 会改当前图表设置,实操时开一张新图表专门挂它,避免把正在看的行情图搞乱。 核心输入分三组。网络结构里 CellsX/CellsY 默认都是 10,即 10×10 神经元网格;HexagonalCell 默认 true 用六边形拓扑,改 false 切矩形;EpochNumber 默认 100 个学习世代;ValidationSetPercent 默认 0 关验证,想用建议约 10%。可视化里 ImageW/ImageH 默认 500 像素,MaxPictures 默认 0 走连续滚动行,设大于 0 则把全部平面排成每行固定数的小图;ShowProgress 默认 true,学习时每秒刷一次网络映像。 模式由文件名切换:DataFileName 和 NetFileName 都空,EA 随机生成 3D 演示集并自教;NetFileName 填了 .som 就进测试模式,直接读已训网络;DataFileName 填 '?' 且网络有效时,EA 按网络里存的范围造随机测试样本。注意网络文件记了特征范围,若喂进去的数值超出原定义区间(比如回撤或成交数为负),不会报错但结果不可靠。 初始化别漏两件事:用 ChartSetInteger 开 CHART_EVENT_MOUSE_MOVE,否则鼠标悬停神经元看不到弹出提示;神经网络算法只靠 OnTimer 触发一次,进去先 EventKillTimer 停表,防止重复跑。下面这段就是 EA 初始化和事件转发的骨架。 用默认参数只把 ImageW/ImageH 降到 230、MaxPictures 设 3,能截到全部平面的图:随机 3D 矢量训出的 Kohonen 映像里,每个神经元标了服务数据,聚类也画了出来。日志会打印聚类信息(默认限 5 条)。之后把 NetFileName 指向刚存的 SOM-20181205-134437.som、DataFileName 写 '?',就能脱离学习集看随机样本的响应平面,此时把图放大、MaxPictures 归 0 更清楚。外汇与贵金属市场波动剧烈、杠杆风险高,这类自组织映射只做特征结构探索,不构成任何方向判定。
CSOMDisplay KohonenMap; class="type">void OnInit() { ChartSetInteger(class="num">0, CHART_EVENT_MOUSE_MOVE, true); EventSetMillisecondTimer(class="num">1); } class="type">void OnChartEvent(class="kw">const class="type">int id, class="kw">const class="type">long &lparam, class="kw">const class="type">class="kw">double &dparam, class="kw">const class="type">class="kw">string &sparam) { KohonenMap.OnChartEvent(id, lparam, dparam, sparam); } class="type">void OnTimer() { EventKillTimer(); MathSrand(RandomSeed); class="type">bool hasOneTestPattern = class="kw">false; if(NetFileName != "") { if(!KohonenMap.Load(NetFileName)) class="kw">return; KohonenMap.DisplayInit(ImageW, ImageH, MaxPictures, ColorScheme, ShowBorders, ShowTitles); Comment("Map ", NetFileName, " is loaded; size: ", KohonenMap.GetWidth(), "*", KohonenMap.GetHeight(), "; features: ", KohonenMap.GetFeatureCount()); if(DataFileName != "") { if(!KohonenMap.LoadPatterns(DataFileName)) { Print("Data loading error, file: ", DataFileName); class=class="str">"cmt">// 生成随机测试矢量 class="type">int n = KohonenMap.GetFeatureCount(); class="type">class="kw">double min, max;
「自造随机样本喂给 SOM 做匹配验证」
这段逻辑展示了在没有现成网络文件时,如何手动构造一组随机特征向量并投进 Kohonen 映射,观察最佳匹配节点(BMU)的输出与误差。外汇与贵金属行情的高维特征若直接套用此类随机初始化,极易因量纲差异导致聚类偏移,属高风险操作,仅适合在 MT5 策略测试器里先跑通流程。 下方代码先按特征数 n 动态扩数组 v,再对每个维度调用 GetFeatureBounds 取上下界,用 rand()/32767 做 [min,max] 均匀随机填充,最后 AddPattern 打上 RANDOM 标签。匹配阶段 GetBestMatchingFeatures 返回节点指针,可打印其坐标、命中次数与 MSE。 double v[]; ArrayResize(v, n); for(int i = 0; i < n; i++) { KohonenMap.GetFeatureBounds(i, min, max); v[i] = (max - min) * rand() / 32767 + min; } KohonenMap.AddPattern(v, "RANDOM"); Print("Random Input:"); ArrayPrint(v); double y[]; CSOMNode *node = KohonenMap.GetBestMatchingFeatures(v, y); Print("Matched Node Output (", node.GetX(), ",", node.GetY(), "); Hits:", node.GetHitsCount(), "; Error:", node.GetMSE(),"; Cluster N", node.GetCluster(), ":"); ArrayPrint(y); KohonenMap.CalculateOutput(v, true); hasOneTestPattern = true; 若连数据文件都没给,代码会生成 1000 组三维演示向量:x[0] 落在 [0,1000]、x[1] 落 [0,1]、x[2] 落 [-1,1],用来对比开/关归一化的映射差异。注意 x[0] 量纲是 x[1] 的千倍,未做 UseNormalization 时 SOM 会倾向被大数值维度主导。 训练分支里 ValidationSetPercent 限制在 1~49 才切分验证集,切分点按数据总量乘 (1-p/100) 取整;ClusterNumber>1 走指定簇数聚类,否则自动估算。开 MT5 把这段贴进 EA 的 OnStart,先试 n=3、CellsX=Y=10,看 BMU 的 MSE 是否随 EpochNumber 下降。
class="type">class="kw">double v[]; ArrayResize(v, n); for(class="type">int i = class="num">0; i < n; i++) { KohonenMap.GetFeatureBounds(i, min, max); v[i] = (max - min) * rand() / class="num">32767 + min; } KohonenMap.AddPattern(v, "RANDOM"); Print("Random Input:"); ArrayPrint(v); class="type">class="kw">double y[]; CSOMNode *node = KohonenMap.GetBestMatchingFeatures(v, y); Print("Matched Node Output(", node.GetX(), ",", node.GetY(), "); Hits:", node.GetHitsCount(), "; Error:", node.GetMSE(),"; Cluster N", node.GetCluster(), ":"); ArrayPrint(y); KohonenMap.CalculateOutput(v, true); hasOneTestPattern = true;
◍ 自组织映射训练完怎么落盘和回检
Kohonen 网络跑完 1000 轮后,典型日志会停在 Overall NMSE=0.09420336270396877,说明映射对样本的总体归一化均方误差约 9.4%,在价格行为聚类里算可用但非极致紧凑。训练收尾时先 Render 进内部 BMP 缓冲,再按是否带测试样本决定画节点还是画全图案,ClusterNumber 非零才标聚类边界。 代码末段把映像存成 SOM-20181205-134437.som,若 NetFileName 为空就按 GetID 自动存盘;随后用随机输入 457.17510 / 0.29727 / 0.57621 做匹配,命中节点 (8,3)、Hits=5、Error=0.05246704285146882,回检误差比训练总体 NMSE 还低,说明该随机样本落进了高密度区。 注意 FileOpen error 5004 是 CSV 路径缺失导致数据装载失败,MT5 里跑这套时先把 ?.csv 换成真实路径,否则后续随机回检不会执行。外汇与贵金属行情高波动,SOM 聚类仅刻画历史形态分布,对未知行情只具概率倾向,不构成方向判定。
ArrayInitialize(vector, class="num">0); KohonenMap.CalculateOutput(vector); } KohonenMap.Render(); class=class="str">"cmt">// 将映像绘制到内部 BMP 缓冲区中 if(hasOneTestPattern) KohonenMap.ShowAllPatterns(); else KohonenMap.ShowAllNodes(); class=class="str">"cmt">// 在 BMP 缓冲区中绘制细胞内标签 if(ClusterNumber != class="num">0) { KohonenMap.ShowClusters(); class=class="str">"cmt">// 标记聚类 } KohonenMap.ShowBMP(SaveImages); class=class="str">"cmt">// 在图表上将文件显示为位图图像,可选择保存到文件中 if(NetFileName == "") { KohonenMap.Save(KohonenMap.GetID()); } } Pass class="num">0 from class="num">1000 class="num">0% Pass class="num">78 from class="num">1000 class="num">7% Pass class="num">157 from class="num">1000 class="num">15% Pass class="num">232 from class="num">1000 class="num">23% Pass class="num">310 from class="num">1000 class="num">31% Pass class="num">389 from class="num">1000 class="num">38% Pass class="num">468 from class="num">1000 class="num">46% Pass class="num">550 from class="num">1000 class="num">55% Pass class="num">631 from class="num">1000 class="num">63% Pass class="num">710 from class="num">1000 class="num">71% Pass class="num">790 from class="num">1000 class="num">79% Pass class="num">870 from class="num">1000 class="num">87% Pass class="num">951 from class="num">1000 class="num">95% Overall NMSE=class="num">0.09420336270396877 Training completed at pass class="num">1000, NMSE=class="num">0.09420336270396877 Clusters [class="num">14]: "R1000" "R1" "R2" N0 class="num">754.83131 class="num">0.36778 class="num">0.25369 N1 class="num">341.39665 class="num">0.41402 -class="num">0.26702 N2 class="num">360.72925 class="num">0.86826 -class="num">0.69173 N3 class="num">798.15569 class="num">0.17846 -class="num">0.37911 N4 class="num">470.30648 class="num">0.52326 class="num">0.06442 Map file SOM-class="num">20181205-class="num">134437.som saved FileOpen error ?.csv : class="num">5004 Data loading error, file: ? Random Input: class="num">457.17510 class="num">0.29727 class="num">0.57621 Matched Node Output(class="num">8,class="num">3); Hits:class="num">5; Error:class="num">0.05246704285146882; Cluster N0: class="num">497.20453 class="num">0.28675 class="num">0.53213
把 Kohonen 类接进你自己的 EA
这几年 MT5 用户已经能拿到 Kohonen 神经网络的开放实现,我们修掉了一些原有 bug,补了配套工具,并用一个演示 EA 跑通了流程。源码直接可挂到你自己的任务里,下一步就是结合具体品种去验证聚类效果。 顺带一提,MQL5 自带的 ALGLIB 移植版已经支持层次聚类,路径在 MQL5/Include/Math/Alglib/dataanalysis.mqh 的 ClusterizerRunAHC,不想自己写 SOM 的可以用它做对照。外汇和贵金属波动受宏观事件驱动,聚类结果稳定性取决于数据分布是否延续,用验证抽样挑地图尺寸和训练时长更稳妥。 作者留了话头:后续会放具体用例,未完待续。你要是真想试,先把那 21.05 KB 的 Kohonen1MQL5.zip 下下来,在策略测试器里用演示 EA 跑一遍 EURUSD 的 H1,看权重图能不能分出趋势和盘整区。