种群优化算法:Nelder-Mead(NM),或单纯形搜索方法·综合运用
(3/3)·从算法原理到回测结果,手把手把 NM 单纯形搜索接进 EA 优化流程
◍ 收缩与飞行两步里的坐标重映射
这段逻辑来自一个多坐标智能体优化器,核心是把当前解往收缩点或反射点推,再离散化回合法区间。收缩段直接拿 contractionCoeff 做线性插值,跳过了原注释里的随机收缩,等于把搜索半径固定按比例收。 [CODE] for (int c = 0; c < coords; c++) { Xo = agent.s.c [c]; Xw = agent.s.p [indW].c [c]; //Xc = Xo + RNDfromCI (0.0, contractionCoeff) * (Xw - Xo); Xc = Xo + contractionCoeff * (Xw - Xo); agent.s.Xc.c [c] = SeInDiSp (Xc, rangeMin [c], rangeMax [c], rangeStep [c]); agent.c [c] = agent.s.Xc.c [c]; } agent.s.operation = contraction; } //—————————————————————————————————————————————————————————————————————————————— //—————————————————————————————————————————————————————————————————————————————— void C_AO_NMm::Flying (S_Agent &agent, int indW) { for (int c = 0; c < coords; c++) { double r1 = RNDfromCI (-1.0, 1.0); r1 = r1 > 0.5 ? 1.0 : -1.0; double r2 = RNDfromCI (1.0, 20.0); r2 = pow (r2, -2.0); if (r1 > 0.0) Xr = cB [c] + Scale (r2, 0.0, 1.0, 0.0, rangeMax [c] - cB [c], false); else Xr = cB [c] - Scale (r2, 0.0, 1.0, 0.0, cB [c] - rangeMin [c], false); //Xr = RNDfromCI (rangeMin [c], rangeMax [c]); agent.s.Xr.c [c] = SeInDiSp (Xr, rangeMin [c], rangeMax [c], rangeStep [c]); agent.c [c] = agent.s.Xr.c [c]; } agent.s.operation = reflection; } //—————————————————————————————————————————————————————————————————————————————— [/CODE] 飞行段先抽 r1 落在 (-1,1),大于 0.5 才取正方向,否则反向;r2 从 (1,20) 抽后再做 -2 次幂,实际落在约 (0.0025, 1.0) 区间,越大的原始值被压得越狠。 别把正态当圣经 r2 用 pow(r2,-2.0) 之后分布严重右偏,小步长占绝大多数,MT5 里把 20.0 调到 5.0 会明显让反射跳变更活跃,可实盘前用历史 tick 回测验证收敛速度差异。 两段最后都调 SeInDiSp 把连续值 snap 到 rangeStep 网格上,这意味着参数若设得比 rangeStep 粗,优化器可能在相邻网格点间空转,外汇与贵金属波动下这种空转会放大过拟合风险。
for (class="type">int c = class="num">0; c < coords; c++) { Xo = agent.s.c [c]; Xw = agent.s.p [indW].c [c]; class=class="str">"cmt">//Xc = Xo + RNDfromCI(class="num">0.0, contractionCoeff) * (Xw - Xo); Xc = Xo + contractionCoeff * (Xw - Xo); agent.s.Xc.c [c] = SeInDiSp(Xc, rangeMin [c], rangeMax [c], rangeStep [c]); agent.c [c] = agent.s.Xc.c [c]; } agent.s.operation = contraction; } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_NMm::Flying(S_Agent &agent, class="type">int indW) { for (class="type">int c = class="num">0; c < coords; c++) { class="type">class="kw">double r1 = RNDfromCI(-class="num">1.0, class="num">1.0); r1 = r1 > class="num">0.5 ? class="num">1.0 : -class="num">1.0; class="type">class="kw">double r2 = RNDfromCI(class="num">1.0, class="num">20.0); r2 = pow(r2, -class="num">2.0); if (r1 > class="num">0.0) Xr = cB [c] + Scale(r2, class="num">0.0, class="num">1.0, class="num">0.0, rangeMax [c] - cB [c], false); else Xr = cB [c] - Scale(r2, class="num">0.0, class="num">1.0, class="num">0.0, cB [c] - rangeMin [c], false); class=class="str">"cmt">//Xr = RNDfromCI(rangeMin [c], rangeMax [c]); agent.s.Xr.c [c] = SeInDiSp(Xr, rangeMin [c], rangeMax [c], rangeStep [c]); agent.c [c] = agent.s.Xr.c [c]; } agent.s.operation = reflection; } class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
NMm 在测试台上的真实分数
把 NMm(Nelder-Mead 方法 M)丢进标准测试台,参数设为 C_AO_NMm:5;1.0;2.0;0.5,每个函数跑 10000 次。Rastrigin 函数上 5/25/500 维得分分别为 0.96607 / 0.76427 / 0.62730,平滑曲面上表现相当能打;但 Forest 与 Megacity(离散)立刻露怯,500 维得分只剩 0.05601 和 0.03357。 横向对比 24 个算法,NMm 总评 39.660,排第 9。前面 SDSm、SSG、DE、HS 都过了 70 分,NMm 和它们不在一个量级,但在无梯度直接搜索里算站稳了。 可视化里能看见群体退化、活点挤成一团,靠 Levy 航班稍微救回一点分散度,收缩图并不稳。第三个 1000 变量测试跑太久没进 GIF,只放了前两个。 外汇与贵金属实盘用这类优化器调参时,高杠杆下模型失效会迅速放大亏损,属高风险操作,回测分数不等于实盘概率。
「一点提醒」
Nelder-Mead 原版在重优化里基本可以弃了:它要在初始阶段把单纯形每个顶点的适应度都算一遍,这在多维搜索空间里直接把效率拖死,所以评级表里只留了改版 NMm。SDS 算法也已从表中删除,仅保留其修改版本。 NMm 的改版优势是外部参数少、在变量少且平滑的函数上结果尚可,但缺点很实打实:实现复杂、难接第三方应用、运算速度低、可伸缩性差、结果分散、还容易陷局部极值。这些优劣都只针对这个特定改版,常规 NM 因结果太弱没进表。 文末附的 24_The_world_of_AO_NM.zip(421.03 KB)里有前几篇算法代码的当前更新版,作者说明多处修改只为提升搜索能力,结论基于实验、不对规范算法绝对准确负责。外汇与贵金属优化回测高风险,实盘前务必在 MT5 策略测试器自跑一遍验证。