种群优化算法:和弦搜索(HS)·进阶篇
📘

种群优化算法:和弦搜索(HS)·进阶篇

第 2/2 篇

◍ 和声搜索的初始化与记忆库生成

这段逻辑实现了和声搜索(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。外汇与贵金属参数优化属高风险操作,这套随机搜索可能陷入局部最优,实盘前务必用历史数据多跑几轮验证。

MQL5 / C++
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 代收敛速度可能更快也可能振荡,外汇与贵金属品种请务必用小本金验证高风险特性。

MQL5 / C++
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 社区账号死活连不上。 实际排查时先看地址栏是否拦了第三方脚本,再清一次缓存,比反复输密码管用。 外汇与贵金属交易本身高风险,任何工具链上的小中断都可能让你错过实时信号,先把通道跑通再谈策略。

常见问题

按搜索边界均匀随机撒点建记忆库即可,别用手拍的固定值,否则容易漏掉可行域边缘的解。
基准测试里步长取搜索域的5%~10%、留存概率0.9上下较稳,太小易陷局部、太大抖动剧烈。
小布可载入你的边界与函数设定,批量跑记忆库初始化与变异组合,把收敛曲线和胜率直接列给你。
噪声掩盖了和声库相似度判断,导致劣解被误留;实测信噪比低于10dB时表现明显下滑。
先用Rastrigin、Sphere等无噪基准函数复现文中收敛代差,确认调通再叠噪声与真实报价序列。