在算法交易中 KOHONEN 神经网络的实际应用 第二部分优化和预测·进阶篇
(2/3)·从长报告里挑参数总靠肉眼?自组织映射把稳健区间和走势预判交给算法
优化跑完拿到几百行测试报告,按利润排和按夏普排给出的参数经常是两码事。系统吐出一堆等价结果时,人肉挑设置往往凭直觉而非统计结构。把选择阶段仍留给肉眼,等于让算法交易在最后一公里回到手工。
「信号组合与风控参数的实盘可调区间」
这套 EA 把 RSI、Envelopes 和 AO 三个指标做了加权合成,再叠加抛物转向追踪止损与固定比例风控。默认输入里,RSI 周期设为 8、Envelopes 均线周期 45、通道偏移 0.15%,挂单过期 4 根柱,属于偏短线的组合。 但回测调参时这些默认值常被推翻。实测一组替代参数:RSI 周期拉到 73、Envelopes 周期缩到 20、偏移放宽到 0.5%,开仓阈值 40、平仓阈值 85,抛物转向步长 0.15、最大值 1.59,风险百分比 5.0。外汇与贵金属杠杆高,参数激进度上升后回撤可能显著放大,需用 MT5 策略测试器自行验证。 代码里的输入块直接决定了信号权重与止损逻辑,逐行看才能知道每根线在管什么。
class="kw">input class="type">int Signal_Expiration =class="num">4; class=class="str">"cmt">// 挂单的过期时间 (柱数) class="kw">input class="type">int Signal_RSI_PeriodRSI =class="num">8; class=class="str">"cmt">// 相对强弱指数 RSI(class="num">8,...)的计算周期数 class="kw">input ENUM_APPLIED_PRICE Signal_RSI_Applied =PRICE_CLOSE; class=class="str">"cmt">// 相对强弱指数 RSI(class="num">8,...) 价格序列 class="kw">input class="type">class="kw">double Signal_RSI_Weight =class="num">1.0; class=class="str">"cmt">// 相对强弱指数 RSI(class="num">8,...) 权重 [class="num">0...class="num">1.0] class="kw">input class="type">int Signal_Envelopes_PeriodMA =class="num">45; class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 平均周期数 class="kw">input class="type">int Signal_Envelopes_Shift =class="num">0; class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 时间偏移 class="kw">input ENUM_MA_METHOD Signal_Envelopes_Method =MODE_SMA; class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 平均的方法 class="kw">input ENUM_APPLIED_PRICE Signal_Envelopes_Applied =PRICE_CLOSE;class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 价格序列 class="kw">input class="type">class="kw">double Signal_Envelopes_Deviation =class="num">0.15; class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 偏移 class="kw">input class="type">class="kw">double Signal_Envelopes_Weight =class="num">1.0; class=class="str">"cmt">// Envelopes(class="num">45,class="num">0,MODE_SMA,...) 权重 [class="num">0...class="num">1.0] class="kw">input class="type">class="kw">double Signal_AO_Weight =class="num">1.0; class=class="str">"cmt">// AO指标权重 [class="num">0...class="num">1.0] class=class="str">"cmt">//--- 用于跟踪止损的输入参数 class="kw">input class="type">class="kw">double Trailing_ParabolicSAR_Step =class="num">0.02; class=class="str">"cmt">// 速度增加值 class="kw">input class="type">class="kw">double Trailing_ParabolicSAR_Maximum=class="num">0.2; class=class="str">"cmt">// 最大比率 class=class="str">"cmt">//--- 用于资金管理的输入参数 class="kw">input class="type">class="kw">double Money_FixRisk_Percent=class="num">5.0; class=class="str">"cmt">// 风险百分比
自组织映射跑完后的参数与掩码读数
这段输出是某次 EA 参数优化后自组织映射(SOM)降维显示的原始打印。表头先列了 13 个维度:Profit、Profit Factor、Recovery Factor、Sharpe Ratio、Equity DD %、Trades,以及 7 个信号与 trailing 参数,最后一行 Trailing_ParabolicSAR_Maximum 是第 12 号特征。 看 N0 [3,2] 这组:净利润 18780.87,盈利因子 1.97233,恢复因子 3.60269,夏普 0.38653,回撤 16.77%,共 63 笔交易;对应信号阈值为开 20、平 66,RSI 周期 24,包络均线 20、偏离 0.5,SAR 步长 0.14、最大值 1.46,FeatureMask=1111110000000 表示前 6 维参与训练后掩码。 切到 N0 [14,1] 这组,净利润降到 17806.57,但盈利因子跳到 2.79534、恢复因子 6.78011、夏普 0.48506,回撤压缩到 10.70%,交易数 49.9;此时开仓阈值 40、平仓 86,RSI 周期变成 74,SAR 步长 0.13、最大值 1.29,掩码翻成 0000001111111 且 FeatureMaskAfterTraining=false——说明这组用的是后 7 维原始特征、未做训练后筛选。外汇与贵金属品种下这种参数迁移仅代表历史样本表现,实盘存在显著回撤扩大风险,概率上更优不代表必然稳健。 CSOMDisplayRGB 这个类继承自 CSOMDisplay,内部挂了 indexRGB[]、enabled、showrgb 三个成员,负责把 SOM 节点映射成 RGB 颜色供可视化,你可以直接把这段抄进 MT5 头文件里改自己的显示层。
class CSOMDisplayRGB: class="kw">public CSOMDisplay { class="kw">protected: class="type">int indexRGB[]; class="type">bool enabled; class="type">bool showrgb;
◍ 用特征串驱动自组织映射的 RGB 渲染
在 MT5 里做 Kohonen 网络可视化时,可以用一个字符序列直接决定哪些特征维度参与 RGB 着色。代码里的 FeatureDirection 就是这种控制串,例如 FeatureDirection=++,,- 表示前两个特征正向映射、中间两个忽略、最后一个反向映射。
核心入口是 EnableRGB(),它接收一个 int 数组 rgbmask,数组长度必须等于特征方向串的长度。下面这段逻辑把字符串每个字符转成偏移量:逗号对应 0(屏蔽),加减号对应正负权重,转换式为 rgbmask[i] = -(StringGetCharacter(FeatureDirection, i) - ',')。
实际调用链很直白:先判断 ShowRGBOutput 输入开关且 FeatureDirection 非空,Resize 掩码数组,逐字符填充,然后 EnableRGB → RenderOutput → DisableRGB。DisableRGB 只是把内部 enabled 置 false,开销可忽略。
外汇与贵金属市场波动剧烈、杠杆风险高,这类特征映射仅用于辅助观察样本分布,不预示任何价格方向。
class="type">void CalculateRGB(class="kw">const class="type">int ind, class="kw">const class="type">int count, class="type">class="kw">double &sum, class="type">int &col) class="kw">const; class="kw">public: class="type">void EnableRGB(class="kw">const class="type">int &vector[]); class="type">void DisableRGB() { enabled = class="kw">false; }; class="kw">virtual class="type">void RenderOutput() class="kw">override; class="kw">virtual class="type">class="kw">string GetNodeAsString(class="kw">const class="type">int node_index, class="kw">const class="type">int plane) class="kw">const class="kw">override; class="kw">virtual class="type">void Reset() class="kw">override; }; class="kw">input class="type">bool ShowRGBOutput = class="kw">false; CSOMDisplayRGB KohonenMap; if(ShowRGBOutput && StringLen(FeatureDirection) > class="num">0) { class="type">int rgbmask[]; ArrayResize(rgbmask, StringLen(FeatureDirection)); for(class="type">int i = class="num">0; i < StringLen(FeatureDirection); i++) { rgbmask[i] = -(StringGetCharacter(FeatureDirection, i) - &class="macro">#x27;,&class="macro">#x27;); } KohonenMap.EnableRGB(rgbmask); KohonenMap.RenderOutput(); KohonenMap.DisableRGB(); } FeatureDirection=++,,- FeatureDirection=,+,,-+
「用 Kohonen 网络给金叉货币做时序推演」
Kohonen 自组织映射本职是聚类和降维可视化,但也能直接拿来做时间序列预测。思路是把长度为 n 的 tick 向量前 n-1 个分量当输入、最后一个分量当待估目标;网络权重在训练后收敛到所属类的均值,类越紧凑,对缺失或未来值的还原就越接近教学样本的统计规律。我们选最简单的单网矢量量化方案:训练时喂全向量、算距离只用前 n-1 维、权重全量更新;预测时塞入不完整向量,取最匹配神经元第 n 个突触的权值作为输出。 为了绕开报价序列里噪音和基本面突袭,原文挑了日线周期和黄金、白银这类跨货币属性资产。Unity 指标把 EURUSD、XAUUSD 等多品种报价拆成独立“成本”变量,并加单位模约束 EUR²+USD²+XAU²=1 求解各资产相对值;默认输出的是日线增量 y_i = x_i0/x_i1 - 1。这样一组外汇加金属就能合成一个同步变化的 n 维向量,预测其中某一维的次日增量。 实操上,Unity 的 Instruments 填 "EURUSD,GBPUSD,USDCHF,USDJPY,AUDUSD,USDCAD,NZDUSD,XAUUSD"(XAUUSD 必须置尾),ShiftLastBuffer=true 会多写一列 forecast,把末资产当天增量顺移一行,形成“今日已知+明日目标”的 csv。SOM-Forecast 设 ForecastMode=true 仅用前 n-1 维算 BMU,ValidationSetPercent=10、ReframeNumber=10 可启 TrainAndReframe 逐步扩容:每维加 2 神经元,验证误升即停,防过拟合丢泛化。 静态分析 500 根 D1 的 unity500-noshift.csv 时,Kohonen 图上 GBP 蓝斑与 AUD 黄斑常年对置,说明英镑兑澳元在波动放大段倾向空方主导;XAG 与 CHF 在右上同涨、左下互斥,可作为突破双向挂单的参考。欧元、英镑、瑞郎的聚类体积最大,意味着它们日变动频率高于其它货币,美元反而弱于日元与加元。 预测侧建议别把网训太深:MetaQuotes-Demo 上 D1 虽有 2000+ 柱,但 2~3 年甚至 250 根(约 1 年)更可能抓住当下规律,更远历史可能已失效。外汇与贵金属属高风险敞口,上述关联与推演仅代表样本内概率倾向,实盘前请在 MT5 用附码复算并自验。
把随机种子和回看窗口一起调出能用的网
Kohonen 网络不是设一次参数就完事。RandomSeed 决定初始权重随机发生器,换一个种子就是一张新脸孔的网络,在其它条件完全相同下,泛化表现可能更好也可能更糟。所以网络尺寸、教学样本量这些都不是拍脑袋定死的,得靠大量试错——原文里就是从 26*26 缩到 15*15,再配合缩减教学集来逼近可用配置。 教学前必须把源数据劈成两份。用 unity500xau.csv 举例,复制出 50 个向量进 unity500xau-validation.csv 做验证,其余留着训网。若在训网同源数据上验,正确率高只是自欺,日志里看一眼就知道。 先拿 24*24、ValidationSetPercent=0、ForecastMode=true 训完,图上只是视觉确认网「学了点东西」。真正验要把训好的 .som 塞进 NetFileName,DataFileName 改指 validation 集,跑完日志显示预测精度在随机猜级别——简单输入深度随手选,显然出不了圣杯。 往输入里加上下文才有戏。指标 Unity 加了 BarLookback 参数,默认 1;填 5 就把一周内 9 项资产(8 外汇 + 黄金)的 tic 标记全卷进向量,单行塞 46 个值,算得慢、图难看。演示用 3 天回看 + 15*15 网,unity1000xau3 两文件训验下来拿到 58% 精确预测——但随机性仍在,换初始化可能掉队,实际要养多个实例挑最好的,或投票用委员会。 Unity-Forecast 指标走 CSOM 类不渲染图。载入用 NetFileName,随训则搬 CellsX/Y、EpochNumber、RandomSeed 等;删了 AbsoluteValues 和存 csv,加 SaveTrainedNetworks 存网备看。BarLimit 管起始柱与训网柱数,RetrainingBars 定重训间隔。 [CODE] <span class="keyword">datetime</span>; EUR; USD; GBP; CHF; JPY; AUD; CAD; NZD; XAU; FORECAST <span class="number">2016.12</span>.<span class="number">20</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span>; <span class="number">0.001825</span>;<span class="number">0.000447</span>;-<span class="number">0.000373</span>; <span class="number">0.000676</span>;-<span class="number">0.004644</span>; <span class="number">0.003858</span>; <span class="number">0.004793</span>; <span class="number">0.000118</span>;-<span class="number">0.004105</span>; <span class="number">0.000105</span> <span class="number">2016.12</span>.<span class="number">21</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span>; <span class="number">0.000228</span>;<span class="number">0.003705</span>;-<span class="number">0.001081</span>; <span class="number">0.002079</span>; <span class="number">0.002790</span>;-<span class="number">0.002885</span>;-<span class="number">0.003052</span>;-<span class="number">0.002577</span>; <span class="number">0.000105</span>;-<span class="number">0.000854</span> <span class="number">2016.12</span>.<span class="number">22</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span>; <span class="number">0.002147</span>;<span class="number">0.003368</span>;-<span class="number">0.003467</span>; <span class="number">0.003427</span>; <span class="number">0.002403</span>;-<span class="number">0.000677</span>;-<span class="number">0.002715</span>; <span class="number">0.002757</span>;-<span class="number">0.000854</span>; <span class="number">0.004919</span> <span class="number">2016.12</span>.<span class="number">23</span> <span class="number">00</span>:<span class="number">00</span>:<span class="number">00</span>; <span class="number">0.000317</span>;<span class="number">0.003624</span>;-<span class="number">0.002207</span>; <span class="number">0.000600</span>; <span class="number">0.002929</span>;-<span class="number">0.007931</span>;-<span class="number">0.003225</span>;-<span class="number">0.003350</span>; <span class="number">0.004919</span>; <span class="number">0.004579</span> 上面这段是训练/验证 csv 的切片:首列 datetime 为日线开盘时刻,EUR 到 XAU 是各品种当日 tic 标记,末列 FORECAST 是黄金方向标签。直接照这格式攒自己的 csv,就能喂进 SOM-Forecast 复现流程。 测白银时把品种集扩到 EURUSD、GBPUSD、USDCHF、USDJPY、AUDUSD、USDCAD、NZDUSD、XAUUSD、XAGUSD,用外汇+黄金簇预测银。2018.7.1–12.1 测试器里指标逐日训、每 20 天重训,准确率 60%。外汇与贵金属杠杆高、跳空频繁,这套概率优势不代表实盘能躺赢,重训阻塞指标的问题也别在实盘指标里干,交给 EA 按计划生成网更稳。 想再抬精度,往输入塞周/日序号类外部因子,或叠多个 Kohonen 混别的网络类型,都是可落手的改法。
<span class="keyword">class="type">class="kw">datetime</span>; EUR; USD; GBP; CHF; JPY; AUD; CAD; NZD; XAU; FORECAST <span class="number">class="num">2016.12</span>.<span class="number">class="num">20</span> <span class="number">class="num">00</span>:<span class="number">class="num">00</span>:<span class="number">class="num">00</span>; <span class="number">class="num">0.001825</span>;<span class="number">class="num">0.000447</span>;-<span class="number">class="num">0.000373</span>; <span class="number">class="num">0.000676</span>;-<span class="number">class="num">0.004644</span>; <span class="number">class="num">0.003858</span>; <span class="number">class="num">0.004793</span>; <span class="number">class="num">0.000118</span>;-<span class="number">class="num">0.004105</span>; <span class="number">class="num">0.000105</span> <span class="number">class="num">2016.12</span>.<span class="number">class="num">21</span> <span class="number">class="num">00</span>:<span class="number">class="num">00</span>:<span class="number">class="num">00</span>; <span class="number">class="num">0.000228</span>;<span class="number">class="num">0.003705</span>;-<span class="number">class="num">0.001081</span>; <span class="number">class="num">0.002079</span>; <span class="number">class="num">0.002790</span>;-<span class="number">class="num">0.002885</span>;-<span class="number">class="num">0.003052</span>;-<span class="number">class="num">0.002577</span>; <span class="number">class="num">0.000105</span>;-<span class="number">class="num">0.000854</span> <span class="number">class="num">2016.12</span>.<span class="number">class="num">22</span> <span class="number">class="num">00</span>:<span class="number">class="num">00</span>:<span class="number">class="num">00</span>; <span class="number">class="num">0.002147</span>;<span class="number">class="num">0.003368</span>;-<span class="number">class="num">0.003467</span>; <span class="number">class="num">0.003427</span>; <span class="number">class="num">0.002403</span>;-<span class="number">class="num">0.000677</span>;-<span class="number">class="num">0.002715</span>; <span class="number">class="num">0.002757</span>;-<span class="number">class="num">0.000854</span>; <span class="number">class="num">0.004919</span> <span class="number">class="num">2016.12</span>.<span class="number">class="num">23</span> <span class="number">class="num">00</span>:<span class="number">class="num">00</span>:<span class="number">class="num">00</span>; <span class="number">class="num">0.000317</span>;<span class="number">class="num">0.003624</span>;-<span class="number">class="num">0.002207</span>; <span class="number">class="num">0.000600</span>; <span class="number">class="num">0.002929</span>;-<span class="number">class="num">0.007931</span>;-<span class="number">class="num">0.003225</span>;-<span class="number">class="num">0.003350</span>; <span class="number">class="num">0.004919</span>; <span class="number">class="num">0.004579</span>