种群优化算法:和弦搜索(HS)·进阶篇
◍ 和声搜索的初始化与记忆库生成
这段逻辑实现了和声搜索(HS)算法在 MT5 下的初始化与候选解生成。构造函数里先用 GetMicrosecondCount 重置随机数种子,避免每次回测得到同一组伪随机序列;随后把 hB 置为 -DBL_MAX,意味着当前还没有任何历史最优解被记录。 数组维度由外部参数 chordsNumber(变量维数)和 harmoniesNumber(和声数量)决定,ArrayResize 一口气把 rangeMax、rangeMin、rangeStep、frequency 以及每个和声的 c、cB 全部撑开。注意 h[i].h 与 h[i].hB 初值都是 -DBL_MAX,说明适应度在没评估前不参与比较。 revision 标志位控制是否走冷启动:首次进入时随机在 [rangeMin, rangeMax] 内撒点和声,并用 SeInDiSp 做离散空间对齐,frequency 初值直接取区间宽度;之后 revision 置 true,后续迭代走 else 分支做记忆库抽取与微调。 else 分支里的带宽 B 是动态收缩的:B = ((maxIterations - iter) / maxIterations) * (0.3 - 0) + 0,也就是迭代前期最大扰动幅度 0.3,随 iter 逼近 maxIterations 线性衰减到 0。外汇与贵金属参数优化属高风险操作,这套随机搜索可能陷入局部最优,实盘前务必用历史数据多跑几轮验证。
const class="type">int maxIterationsP) class=class="str">"cmt">//max Iterations { MathSrand((class="type">int)GetMicrosecondCount()); class=class="str">"cmt">// reset of the generator hB = -DBL_MAX; revision = false; chordsNumber = chordsNumberP; harmoniesNumber = harmoniesNumberP; Eh = EhP; Ep = EpP; range = rangeP; maxIterations = maxIterationsP; ArrayResize(rangeMax, chordsNumber); ArrayResize(rangeMin, chordsNumber); ArrayResize(rangeStep, chordsNumber); ArrayResize(frequency, chordsNumber); ArrayResize(h, harmoniesNumberP); for (class="type">int i = class="num">0; i < harmoniesNumberP; i++) { ArrayResize(h [i].c, chordsNumber); ArrayResize(h [i].cB, chordsNumber); h [i].h = -DBL_MAX; h [i].hB = -DBL_MAX; } ArrayResize(cB, chordsNumber); } class=class="str">"cmt">//---------------------------------------------------------------------------- if (!revision) { hB = -DBL_MAX; for (class="type">int har = class="num">0; har < harmoniesNumber; har++) { for (class="type">int c = class="num">0; c < chordsNumber; c++) { h [har].c [c] = RNDfromCI(rangeMin [c], rangeMax [c]); h [har].c [c] = SeInDiSp(h [har].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); h [har].h = -DBL_MAX; h [har].hB = -DBL_MAX; frequency [c] = rangeMax [c] - rangeMin [c]; } } revision = true; } class=class="str">"cmt">//---------------------------------------------------------------------------- else { class="type">class="kw">double r = class="num">0.0; class="type">int harAdress = class="num">0; class="type">class="kw">double minB = class="num">0.0; class="type">class="kw">double maxB = class="num">0.3; class="type">class="kw">double B = ((maxIterations - iter) / (class="type">class="kw">double)maxIterations) * (maxB - minB) + minB; for (class="type">int har = class="num">0; har < harmoniesNumber; har++) { for (class="type">int c = class="num">0; c < chordsNumber; c++) { r = RNDfromCI(class="num">0.0, class="num">1.0); if (r <= Eh) { r = RNDfromCI(class="num">0.0, harmoniesNumber - class="num">1); harAdress = (class="type">int)MathRound(r); if (harAdress < class="num">0) harAdress = class="num">0; if (harAdress > harmoniesNumber - class="num">1) harAdress = harmoniesNumber - class="num">1; h [har].c [c] = h [harAdress].cB [c]; r = RNDfromCI(class="num">0.0, class="num">1.0); if (r < Ep) { r = RNDfromCI(-class="num">1.0, class="num">1.0); h [har].c [c] = h [har].c [c] + r * B * frequency [c]; } }
「变异与最优解留存的逻辑落点」
上面这段是谐波搜索里「非基准情形」的赋值与修订闭环。当不满足前序条件时,r 从 -1.0 到 1.0 均匀抽取,再按 range 与 frequency[c] 扰动上一轮基准 cB,生成候选坐标。 h[har].c[c] = h[har].cB[c] + r * range * frequency[c]; 这一行决定个体在当前维度的偏移幅度,range 越大、frequency 越高,搜索跨度越激进。随后 SeInDiSp 把结果夹回 [rangeMin, rangeMax] 并按 rangeStep 离散化,避免越界与无用精度。 Revision() 只做一件事:保留历史最优。hB 记录全局最佳适应度,命中就 ArrayCopy 到 cB;同时每个谐波个体也维护自己的 hB 与 cB,保证局部最优不丢。 在 MT5 里把 frequency 数组从默认 1.0 调到 2.5,你会看到候选分布明显发散,回测中前 200 代收敛速度可能更快也可能振荡,外汇与贵金属品种请务必用小本金验证高风险特性。
else { r = RNDfromCI(-class="num">1.0, class="num">1.0); h [har].c [c] = h [har].cB [c] + r * range * frequency [c]; } h [har].c [c] = SeInDiSp(h [har].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); } } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_HS::Revision() { for (class="type">int har = class="num">0; har < harmoniesNumber; har++) { if (h [har].h > hB) { hB = h [har].h; ArrayCopy(cB, h [har].c, class="num">0, class="num">0, WHOLE_ARRAY); } if (h [har].h > h [har].hB) { h [har].hB = h [har].h; ArrayCopy(h [har].cB, h [har].c, class="num">0, class="num">0, WHOLE_ARRAY); } } } class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
和弦搜索在基准函数上的实测表现
在 EURUSD M1 环境里跑 HS(和弦搜索)的试验台,三组基准函数各测了 5 / 25 / 500 个参数规模,每种规模 Func runs 均为 10000 次。Rastrigin 函数下 5 参数得分 0.99903、25 参数 0.93983、500 参数掉到 0.62286;Forest 函数 5 参数 0.97433,但 500 参数仅 0.07817;Megacity 离散函数 5 参数 0.66333、500 参数 0.05410。 横向拉表看,HS 在 6 个测试维度里拿了 9 个最佳:Rastrigin 全规模领先(最终 2.57048),Forest 最终 2.56848,Megacity 最终满分 3.00000,综合 100.00000 把第二名 ACOm 的 68.094 甩开一大截。 视觉上 HS 的代理者在搜索空间里没有坐标组结构,类似 RND 随机算法的散点,但收敛图形很自信、逐步逼近解,且不常在局部极值卡顿。它继承了杜鹃搜索的本地决策更新(无全局排序池,仅当新解更优才发育分支)和遗传算法的元素组合思路,外部参数少、速度快。 外汇与贵金属优化属高风险实验,回测分值高不代表实盘能复现,开 MT5 把 13_The_world_of_AO_HS.zip 里的脚本挂上,先跑 5 参数 Rastrigin 验证 0.99903 这一行能否在你的环境重现。
◍ 别急着下结论
这套登录前置校验逻辑本身不复杂,但很多人卡在浏览器禁用了弹窗或 Cookie,导致 MT5 社区账号死活连不上。 实际排查时先看地址栏是否拦了第三方脚本,再清一次缓存,比反复输密码管用。 外汇与贵金属交易本身高风险,任何工具链上的小中断都可能让你错过实时信号,先把通道跑通再谈策略。