种群优化算法:灰狼优化器(GWO)·进阶篇
📘

种群优化算法:灰狼优化器(GWO)·进阶篇

第 2/2 篇

灰狼包围算子的坐标更新实现

这段实现把灰狼优化里「包围猎物」的向量公式拆成了两层循环:普通狼(索引 alphaNumber 到 wolvesNumber-1)会同时参考前 alphaNumber 只头狼的位置来更新自己的每个坐标,头狼自身则只朝当前最优解 cB 做单步逼近。 外层 a 由 sqrt(2.0*(1.0 - epochNow/epochCount)) 算出,随迭代轮次从约 1.414 衰减到 0,控制探索与开发的切换;r1、r2 各在 [0,1] 随机,Ai 与 Ci 由此派生,直接决定步长方向。 [CODE] double a = sqrt (2.0 * (1.0 - (epochNow / epochCount))); double r1 = 0.0; double r2 = 0.0; double Ai = 0.0; double Ci = 0.0; double Xn = 0.0; double min = 0.0; double max = 1.0; //omega----------------------------------------------------------------------- for (int w = alphaNumber; w < wolvesNumber; w++) { Xn = 0.0; for (int c = 0; c < coordinates; c++) { for (int abd = 0; abd < alphaNumber; abd++) { r1 = RNDfromCI (min, max); r2 = RNDfromCI (min, max); Ai = 2.0 * a * r1 - a; Ci = 2.0 * r2; Xn += wolves [abd].c [c] - Ai * (Ci * wolves [abd].c [c] - wolves [w].c [c]); } wolves [w].c [c] = Xn /= (double)alphaNumber; } ReturnToRange (wolves [w]); } //alpha, beta, delta---------------------------------------------------------- for (int w = 0; w < alphaNumber; w++) { for (int c = 0; c < coordinates; c++) { r1 = RNDfromCI (min, max); r2 = RNDfromCI (min, max); Ai = 2.0 * a * r1 - a; Ci = 2.0 * r2; wolves [w].c [c] = cB [c] - Ai * (Ci * cB [c] - wolves [w].c [c]); } ReturnToRange (wolves [w]); } //—————————————————————————————————————————————————————————————————————————————— void C_AO_GWO::RevisionAlphaStatus () { SortingWolves (); if (wolves [0].p > pB) { pB = wolves [0].p; ArrayCopy (cB, wolves [0].c, 0, 0, WHOLE_ARRAY); } } //—————————————————————————————————————————————————————————————————————————————— [/CODE] 逐行拆解:第1行 a 是收敛因子,epochNow 越接近 epochCount,a 越趋近 0,狼群从广域搜索收拢到局部;第13–16行每只普通狼对头狼做加权位置差累加,第22行取平均写回坐标,避免单头狼主导;第31–38行头狼直接以 cB 为猎物中心做包围,不再参考同级。 RevisionAlphaStatus 在每代排序后把最优狼的位置拷进 cB,pB 记录历史最好适应度;若你在 MT5 里把 alphaNumber 设成 3,就意味着 beta、delta 也参与引导,狼群可能更快陷进局部极值,建议先用 EURUSD 五分钟样本跑 200 代看收敛曲线。

MQL5 / C++
class="type">class="kw">double a  = sqrt(class="num">2.0 * (class="num">1.0 - (epochNow / epochCount)));
class="type">class="kw">double r1 = class="num">0.0;
class="type">class="kw">double r2 = class="num">0.0;
class="type">class="kw">double Ai = class="num">0.0;
class="type">class="kw">double Ci = class="num">0.0;
class="type">class="kw">double Xn = class="num">0.0;
class="type">class="kw">double min = class="num">0.0;
class="type">class="kw">double max = class="num">1.0;
class=class="str">"cmt">//omega-----------------------------------------------------------------------
for (class="type">int w = alphaNumber; w < wolvesNumber; w++)
{
  Xn = class="num">0.0;
  for (class="type">int c = class="num">0; c < coordinates; c++)
  {
    for (class="type">int abd = class="num">0; abd < alphaNumber; abd++)
    {
      r1 = RNDfromCI(min, max);
      r2 = RNDfromCI(min, max);
      Ai = class="num">2.0 * a * r1 - a;
      Ci = class="num">2.0 * r2;
      Xn += wolves [abd].c [c] - Ai * (Ci * wolves [abd].c [c] - wolves [w].c [c]);
    }
    wolves [w].c [c] = Xn /= (class="type">class="kw">double)alphaNumber;
  }
  ReturnToRange(wolves [w]);
}
class=class="str">"cmt">//alpha, beta, delta----------------------------------------------------------
for (class="type">int w = class="num">0; w < alphaNumber; w++)
{
  for (class="type">int c = class="num">0; c < coordinates; c++)
  {
    r1 = RNDfromCI(min, max);
    r2 = RNDfromCI(min, max);
    Ai = class="num">2.0 * a * r1 - a;
    Ci = class="num">2.0 * r2;
    wolves [w].c [c] = cB [c] - Ai * (Ci * cB [c] - wolves [w].c [c]);
  }
  ReturnToRange(wolves [w]);
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_GWO::RevisionAlphaStatus()
{
  SortingWolves();
  if (wolves [class="num">0].p > pB)
  {
    pB = wolves [class="num">0].p;
    ArrayCopy(cB, wolves [class="num">0].c, class="num">0, class="num">0, WHOLE_ARRAY);
  }
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————

「给测试函数补上客观性约束」

做优化算法基准测试时,Skin、Forest、Megacity 这几个函数已经覆盖了多局部极值、不可微点、离散面等复杂性维度。但原版漏掉了一个关键缺陷:全局极值若落在定义域边界或正中心,算法可能靠越界取值或取均值刷出虚假高分。 新约束很直接——全局极值不许在边界,也不许在坐标中心;全局最小值必须压到中心,用来抵消“范围内取平均即达标”的假象。按这个改完边界并把中心偏移到最小值后,纯随机生成的参数在整个函数域里只能拿到约最大值 50% 的平均得分,而不是蒙混过关。 Skin 是平滑多极值面,唯一全局极值附近梯度极弱,容易让算法卡在某个局部峰,蜂群(ABC)就常暴露这种“懒得跳坑”的毛病。Forest 混了平滑与不可微极值,是典型的“大海捞针”,变量一多全局最大极难找,蚁群(ACO)会表现出直插目标的路径特征。Megacity 则是单全局加几个局部的离散问题,均匀下限不提供任何梯度指向,纯靠表面复杂度拖慢收敛。 代码层补了一行越界检查:之前算法能返回定义范围外的虚高函数值,现在传参超界直接拦掉。外汇与贵金属相关的参数优化属高风险,回测漂亮不代表实盘能复现,开 MT5 把这几个函数跑一遍随机搜索就能验证约 50% 均值的现象。

◍ 蚁群与蜂群在 EURUSD 测试台上的得分对照

测试台右侧的收敛图里,绿线是两个变量的函数收敛,蓝线 40 个变量,红线 1000 个变量;大黑圈是全局最大值,小黑圈是当前算法解,白线十字是几何中心(全局最小),白点是平均中间解。表格去掉了收敛速度指示线,改为看动画直观判断,并补了算法描述列。 蚁群优化 ACOm 在 EURUSD M1 上跑满 10000 次函数:1 个 Skin 得 4.844、Score 0.98229;500 个 Skin 掉到 1.258、Score 0.12602。Forest 场景下 1 个得 1.768、Score 1.00000,500 个反而 0.204、Score 0.11521。综合 C_AO_ACOm 全量得分 0.49805。 人工蜂群 ABCm 同条件:Skin 1 个 Score 1.00000,500 个掉到 0.08076;Megacity 1 个 Score 1.00000(result 12.0),500 个仅 0.02823。综合 C_AO_ABCm 全量得分 0.46107,略低于蚁群。 两种算法都呈现「种群数越少单场景越准、越多越散」的倾向,外汇与贵金属实盘套用时须注意这类优化器过拟合高风险,建议直接开 MT5 把日志里的 Func runs 10000 段抄进自己的回测脚本核对。

种群规模对优化器分数的侵蚀曲线

在 EURUSD M1 上跑同一套测试框架,ABC 优化器在 1 个 Skin 粒子时拿到 4.89068 的 Func 值、Score 0.99339,但把种群扩到 500 个 Skin 后 Func 跌到 1.19584、Score 只剩 0.11118。Forest 与 Megacity 两类拓扑也呈现同一走向:1 个粒子时 Score 分别为 0.99934 和 0.85000,500 个时降到 0.04215 和 0.03130。 PSO 对照组的数字更刺眼——1 个 Megacity 粒子直接刷出 Func 12.0、Score 1.00000,可 500 个同类型粒子时 Score 崩到 0.02233。ABC 全量总分 0.46043,PSO 全量总分 0.40837,两者都随粒子数膨胀而显著劣化。 外汇与贵金属属高风险品种,这类单品种 M1 回测分数不能直接外推到实盘。开 MT5 把种群参数从 1 调到 500 复跑,能直观看到 Score 衰减,调参时别盲目加粒子。

「灰狼优化器在三类测试函数上的实测表现」

在 EURUSD M1 上跑了一轮优化器横评,灰狼优化(GWO)与随机搜索(RND)各自对 Skin、Forest、Megacity 三类测试函数做了 1 / 20 / 500 个个体的 10000 次函数求值。GWO 在单个体 Skin 上得分 0.99900,500 个体时跌到 0.18924;RND 同条件分别是 0.99932 与 0.06827,说明 GWO 对平滑多变量函数收敛性确实更强。 Forest 尖锐极大函数是 GWO 的软肋:1 个体得分 0.83844,500 个体仅 0.02555,在参测算法里排末位。Megacity 离散函数上 GWO 单个体拿满 1.00000,但 500 个体掉到 0.02187,扩展性偏低。 汇总看,GWO 全量评分 0.41577,略高于 PSO 的 0.40837 和 RND 的 0.38163,但不及 ACOm 的 0.49805。外汇与贵金属优化涉及杠杆与滑点,回测高分不等于实盘稳健,实盘前务必在 MT5 策略测试器用自己的品种复跑。 GWO 的硬伤是离散、不可微函数扩展性低,且容易卡在局部极值;优势则是平滑函数上收敛快、计算量和 PSO 同级。开 MT5 加载文末的 oGWO 源码,把 Test_AO_GWO 里的种群规模从 1 改到 500,能直接观察 Score 随维度崩塌的曲线。

◍ 记住这一条就够了

作者自 2007 年起持续打磨机器学习、AI 优化与预测类系统,文中罗列了 EMA、BSA、DEA、ES、BBO、DOS、CA 等一整套元启发式算法,社区里巴西交易者曾直接在评论区喊话平台方,希望在 MT5 优化器里原生支持这些目标,用户其实可在 OnTester() 自行挂接。 代码块里那几行 OptimizerSetEngine 调用,是把蚁群、布谷鸟、人工蜂群、灰狼、粒子群直接切进优化器的入口;外汇与贵金属市场高杠杆、滑点随机,这类智能搜索只能提高参数挖掘效率,不保证样本外收益。 真要落地,开 MT5 把上面代码粘进 EA 头部的 OnInit,跑一次多品种回测,对比默认遗传引擎的收敛代数,就知道哪类群智能更贴合你的品种波动结构。

MQL5 / C++
OptimizerSetEngine("ACO"); class=class="str">"cmt">// 蚂蚁群优化
OptimizerSetEngine("COA"); class=class="str">"cmt">// cuckoo 优化算法
OptimizerSetEngine("ABC"); class=class="str">"cmt">// 人工蜂群
OptimizerSetEngine("GWO"); class=class="str">"cmt">// 灰狼优化器
OptimizerSetEngine("PSO"); class=class="str">"cmt">// 粒子群优化

常见问题

按 a 从 2 线性降到 0 算系数,再用三头狼位置加权求新坐标;写代码时先打印中间系数排查衰减是否同步。
同测试台对照下蜂群在收敛速度上略占优,但蚁群在约束函数上更稳;以你用的目标函数类型为准选。
可以,小布能调用内置测试台跑多算法得分对照,并标出最优参数区间,你只需选品种和函数。
不是,规模过大会因个体竞争稀释导致分数侵蚀;实测 30~50 规模在多数测试函数上更稳。
单峰只看收敛效率,多峰才反映逃局部能力;实盘参数寻优以多峰实测表现为主要参考。