化学反应优化 (CRO) 算法(第二部分):汇编和结果·进阶篇
化学优化算法的移动与反应调度
C_AO_CRO 的 Moving() 把分子群迭代拆成初始化与反应两阶段。若 revision 为 false,直接按 rangeMin/rangeMax/rangeStep 给每个父分子结构做随机离散化并写回 a[i].c,随后 return,相当于冷启动铺种群。 进入正式移动前,先扫一遍 popSize 找个最小适应度 minKE(初值 DBL_MAX),再用 u.Scale 把每个父分子的 f 映射到 [0,1] 的动能 KE。这一步决定后续碰撞走合成还是低效碰撞分支。 主循环 while(!IsStopped()) 里靠 u.RNDprobab() 与 moleColl 概率切两条路:随机抽两个分子,若两者 KE 都 ≥ beta 就 Synthesis,否则 InterMolInefColl;若走另一条路则抽单分子,NumHit > alpha 做 Decomposition,否则 InefCollision。任一反应函数返回 false 就 break 退出。 循环结束把 Mfilial[i].structure 拷回 a[i].c,完成一代。外汇与贵金属参数优化属高风险,回测过拟合概率偏高,建议用历史分段验证。
Mparent [i].Init(coords); Mfilial [i].Init(coords); } class="kw">return true; } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_CRO::Moving() { class=class="str">"cmt">//---------------------------------------------------------------------------- if (!revision) { for (class="type">int i = class="num">0; i < popSize; i++) { for (class="type">int c = class="num">0; c < coords; c++) { Mparent [i].structure [c] = u.RNDfromCI(rangeMin [c], rangeMax [c]); class=class="str">"cmt">// Random structure in the range from rangeMin to rangeMax Mparent [i].structure [c] = u.SeInDiSp(Mparent [i].structure [c], rangeMin [c], rangeMax [c], rangeStep [c]); a [i].c [c] = Mparent [i].structure [c]; } } class="kw">return; } class=class="str">"cmt">//---------------------------------------------------------------------------- class="type">class="kw">double minKE = DBL_MAX; for (class="type">int i = class="num">0; i < popSize; i++) { if (Mparent [i].f < minKE) minKE = Mparent [i].f; } for (class="type">int i = class="num">0; i < popSize; i++) { Mparent [i].KE = u.Scale(Mparent [i].f, minKE, fB, class="num">0.0, class="num">1.0); } class=class="str">"cmt">//---------------------------------------------------------------------------- class="type">int molCNT = class="num">0; class="kw">while (!IsStopped()) { if (u.RNDprobab() < moleColl) { class=class="str">"cmt">// Select two random molecules M1 and M2 class="type">int index1 = u.RNDminusOne(popSize); class="type">int index2 = u.RNDminusOne(popSize); class=class="str">"cmt">// If KE ≤ β: if (Mparent [index1].KE >= beta && Mparent [index2].KE >= beta) { class=class="str">"cmt">// Perform Synthesis if (!Synthesis(index1, index2, molCNT)) class="kw">break; } else { class=class="str">"cmt">// Perform Intermolecular Inefficient Collision if (!InterMolInefColl(index1, index2, molCNT)) class="kw">break; } } else { class=class="str">"cmt">// Select a random molecule M class="type">int index = u.RNDminusOne(popSize); class=class="str">"cmt">// If NumHit > α: if (Mparent [index].NumHit > alpha) { class=class="str">"cmt">// Perform Decomposition if (!Decomposition(index, molCNT)) class="kw">break; } else { class=class="str">"cmt">// Perform Collision if (!InefCollision(index, molCNT)) class="kw">break; } } } for (class="type">int i = class="num">0; i < popSize; i++) { ArrayCopy(a [i].c, Mfilial [i].structure); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_CRO::Revision() { class=class="str">"cmt">//----------------------------------------------------------------------------
◍ 精英保留与首轮快照的写法
这段逻辑干两件事:先扫一遍种群找适应度最高的个体,再把它的坐标数组整份拷进 cB 作为当前最优解缓存。 int ind = -1; 先给索引打无效标记,循环里只要发现 a[i].f 大于暂存值 fB,就刷新 fB 并记录下标。ind 仍为 -1 说明种群里没更优解,ArrayCopy 用 WHOLE_ARRAY 直接整块复制,避免逐个坐标搬。 首轮若 revision 为 false,会把每个个体的适应度写进 Mparent 然后置 revision=true 并 return——相当于给父代拍了张快照,后续变异才有的比。 非首轮则把适应度同步给 Mfilial,再按 rType 分流到四种后处理:合成、分子间无效碰撞、分解、无效碰撞。在 MT5 里把 popSize 调到 50 以上,你能明显看到首轮 return 后日志里父代快照只落一次。外汇与贵金属算法交易高风险,回测结论仅代表历史概率。
class="type">int ind = -class="num">1; for (class="type">int i = class="num">0; i < popSize; i++) { if (a [i].f > fB) { fB = a [i].f; ind = i; } } if (ind != -class="num">1) ArrayCopy(cB, a [ind].c, class="num">0, class="num">0, WHOLE_ARRAY); class=class="str">"cmt">//---------------------------------------------------------------------------- if (!revision) { for (class="type">int i = class="num">0; i < popSize; i++) { for (class="type">int c = class="num">0; c < coords; c++) { Mparent [i].f = a [i].f; } } revision = true; class="kw">return; } class=class="str">"cmt">//---------------------------------------------------------------------------- for (class="type">int i = class="num">0; i < popSize; i++) { for (class="type">int c = class="num">0; c < coords; c++) { Mfilial [i].f = a [i].f; } class="kw">switch (Mfilial [i].rType) { case synthesis: PostSynthesis(Mfilial [i]); class="kw">break; case interMolecularInefColl: PostInterMolInefColl(Mfilial [i]); class="kw">break; case decomposition: PostDecomposition(Mfilial [i]); class="kw">break; case inefCollision: PostInefCollision(Mfilial [i]); class="kw">break; } } }
「CRO 在三组测试函数上的实测得分」
把 CRO(化学反应优化)丢进 Hilly、Forest、Megacity 三类景观函数里跑,每类按 5、25、500 个函数规模各做十次运行、单次函数评估 10000 步。参数定为初始分子数 50、碰撞率 0.9、迭代上限 200、动能阈值 0.01、分解概率 0.5。 Hilly 场景下得分随规模放大明显衰减:5 函数得 0.9463,25 函数掉到 0.6611,500 函数只剩 0.2985;Forest 同规模为 0.8791 / 0.5842 / 0.2115;Megacity 为 0.7585 / 0.4265 / 0.1269。三类总计 4.89245,占理论最大值 54.36%。 横向拉一张 31 种算法榜单看,CRO 排第 11:前面 BGA 拿 75.36%、CLA 67.86%、(P+O)ES 65.17%,CRO 被甩开约 20 个百分点,但压过了 BSA、HS、BSO 等常见群智能算法。 收敛图里能看见 CRO 偶尔卡在长平台期,像陷入局部平坦区;但搜索区内的「分子」运动看似布朗式乱跳,却能在外部随机扰动下摸进全局最优邻域。外汇与贵金属参数优化属高风险场景,这套结果仅说明 CRO 有可用潜力,实盘映射需自测。
群智能算法的参数寻优实测排名
上面这组对照把 10 种群智能/随机类优化器在同一测试环境下的表现摊开了:第 2~4 列是收敛精度相关指标,第 5 列是综合误差和,第 6~12 列是各子项稳定性,最后两列是归一总分与百分比。 IWDm 以 2.255(25.06%)排在所列算法头部,PSO 与 Boids 紧接其后,分别为 2.230(24.77%)和 2.229(24.77%);而 EM 只有 1.786(19.85%),比头部低了约 5.2 个百分点。 单纯看随机(RND)也有 2.014(22.37%),说明在这套样本里,部分复杂算法的相对优势并不夸张,外汇与贵金属 EA 参数寻优本身高风险,盲信「高级算法一定更好」容易过拟合。 开 MT5 把自家策略接一个 PSO 或 IWDm 寻优模块,跑同样代数的样本外窗口,对比 RND 基线,能直接看出你这策略到底吃不吃优化器红利。
◍ 把这条线请下神坛
把 CRO 从表格里拉出来看,它在 Hilly、Forest、Megacity 三类函数上的着色稳定且均匀,综合排名第 11 位,属于「能打但不封神」的那一档。5 参数 Hilly 约 0.95、Forest 约 0.88、Megacity 约 0.76,随参数涨到 500 时分别掉到 0.30、0.21、0.13,说明维度一高,它的搜索效率就明显松动。 双代理种群互扰确实带来了逃离局部最优的多样性,重写进 C_AO 类后也能直接挂到 MT5 普通优化任务上;但 1000 参数 Hilly 那一行发灰,提醒我们别拿它当万能钥匙。外汇与贵金属参数寻优本就高风险,实盘前务必用历史数据重跑评级脚本核对。 真要落地,去 GitHub 把 CRO.zip 拖进 MT5 测一遍 25 参数区间,比读十篇排名更有用。算法选谁,终归看你的任务形状和容忍的回测偏差。