种群优化算法:灰狼优化器(GWO)·进阶篇
灰狼包围算子的坐标更新实现
这段实现把灰狼优化里「包围猎物」的向量公式拆成了两层循环:普通狼(索引 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 代看收敛曲线。
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,跑一次多品种回测,对比默认遗传引擎的收敛代数,就知道哪类群智能更贴合你的品种波动结构。
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">// 粒子群优化