种群优化算法:二进制遗传算法(BGA)。第 II 部分·综合运用
(3/3)·把 BGA 的种群初始化、算子与终止条件拼成可跑的优化闭环,跳过这一步容易只懂概念不会落地
◍ 染色体倒位与变异的执行细节
遗传算法里的交叉段拼接完,还要做倒位(inversion)和变异(mutation)才能生成新个体。倒位就是随机选一个断点 p1,把染色体后半段搬到临时数组头部、前半段接尾部,再整体写回,相当于打乱基因顺序但不改基因本身。 代码里用 RNDfromCI(0.0,1.0) 取均匀随机数 r,当 r < inversionProbab 才触发倒位;p1 越界时强制钳到 lengthChrome-1。这一步的概率参数直接决定种群多样性,外汇与贵金属行情非线性强,倒位概率设太高可能让已收敛的参数组合被撕碎,属高风险调参。 变异则遍历每个基因位 len,r < mutationProbab 就把 0/1 翻转。之后调 ExtractGenes() 解码,再用 SeInDiSp() 把连续参数约束回 [rangeMin,rangeMax] 并按 rangeStep 离散化。popSize 个新个体全部 marked calculated=true 才算这代繁殖完。 Revision() 负责把子代并回父代池排序,若头名 fitness 超过历史最佳 fB 就更新 cB 最优基因数组——这是你开 MT5 跑 EA 后能在日志里盯的收敛信号。
ArrayCopy(points, poRND, class="num">1, class="num">0, WHOLE_ARRAY); points [class="num">0] = class="num">0; points [pCount + class="num">1] = lengthChrome - class="num">1; r = RNDfromCI(class="num">0.0, class="num">1.0); class="type">int startPoint = r > class="num">0.5 ? class="num">0 : class="num">1; for (class="type">int p = startPoint; p < pCount + class="num">2; p += class="num">2) { if (p < pCount + class="num">1) { for (class="type">uint len = points [p]; len < points [p + class="num">1]; len++) a [i].chromosome [len] = parents [pos].chromosome [len]; } } } class=class="str">"cmt">//perform an inversion------------------------------------------------------ class=class="str">"cmt">//(break the chromosome, swap the received parts, connect them together) r = RNDfromCI(class="num">0.0, class="num">1.0); if (r < inversionProbab) { p1 = (class="type">int)RNDfromCI(class="num">0.0, lengthChrome); if (p1 >= lengthChrome) p1 = lengthChrome - class="num">1; class=class="str">"cmt">//copying the second part to the beginning of the temporary array for (class="type">uint len = p1; len < lengthChrome; len++) tempChrome [len - p1] = a [i].chromosome [len]; class=class="str">"cmt">//copying the first part to the end of the temporary array for (class="type">uint len = class="num">0; len < p1; len++) tempChrome [lengthChrome - p1 + len] = a [i].chromosome [len]; class=class="str">"cmt">//copying a temporary array back for (class="type">uint len = class="num">0; len < lengthChrome; len++) a [i].chromosome [len] = tempChrome [len]; } class=class="str">"cmt">//perform mutation--------------------------------------------------------- for (class="type">uint len = class="num">0; len < lengthChrome; len++) { r = RNDfromCI(class="num">0.0, class="num">1.0); if (r < mutationProbab) a [i].chromosome [len] = a [i].chromosome [len] == class="num">1 ? class="num">0 : class="num">1; } a [i].ExtractGenes(); for (class="type">int c = class="num">0; c < coords; c++) a [i].c [c] = SeInDiSp(a [i].c [c], rangeMin [c], rangeMax [c], rangeStep [c]); a [i].calculated = true; } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_BGA::Revision() { class=class="str">"cmt">//---------------------------------------------------------------------------- for (class="type">int i = parentPopSize; i < parentPopSize + popSize; i++) { parents [i] = a [i - parentPopSize]; } Sorting(parents, parentPopSize + popSize); if (parents [class="num">0].f > fB) { fB = parents [class="num">0].f; ArrayCopy(cB, parents [class="num">0].c, class="num">0, class="num">0, WHOLE_ARRAY); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_BGA::PreCalcRoulette() { roulette [class="num">0].start = parents [class="num">0].f;
「轮盘赌选择里那一点防退化补偿」
这段遗传算法父代筛选代码里,轮盘区间不是简单按适应度比例铺开的。前 parentPopSize-1 个个体的区间长度用自身适应度减去最差个体适应度,等于把全局最差当基线抬了一截,避免弱势群体区间被压成零。 末尾那个 else 分支单独处理了最后一名:它的区间长度取前一名与自身适应度差值的 0.1 倍,而不是常规差值。这个 0.1 的缩放是刻意留的逃生口——即使最差个体适应度极低,仍保留约十分之一相对缝隙被抽中,降低种群早熟收敛概率。 SpinRoulette 函数在总区间 [roulette[0].start, roulette[parentPopSize-1].end] 内均匀取随机数 r,线性扫一遍落点返回索引。你在 MT5 里接这套逻辑时,可以把 0.1 改成外部参数,回测不同补偿系数下黄金 1H 参数寻优的多样性衰减曲线。外汇与贵金属杠杆高,遗传寻优结果仅作概率参考,实盘须控仓。
roulette [class="num">0].end = roulette [class="num">0].start + (parents [class="num">0].f - parents [parentPopSize - class="num">1].f); for (class="type">int s = class="num">1; s < parentPopSize; s++) { if (s != parentPopSize - class="num">1) { roulette [s].start = roulette [s - class="num">1].end; roulette [s].end = roulette [s].start + (parents [s].f - parents [parentPopSize - class="num">1].f); } else { roulette [s].start = roulette [s - class="num">1].end; roulette [s].end = roulette [s].start + (parents [s - class="num">1].f - parents [s].f) * class="num">0.1; } } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">int C_AO_BGA::SpinRoulette() { class="type">class="kw">double r = RNDfromCI(roulette [class="num">0].start, roulette [parentPopSize - class="num">1].end); for (class="type">int s = class="num">0; s < parentPopSize; s++) { if (roulette [s].start <= r && r < roulette [s].end) class="kw">return s; } class="kw">return class="num">0; } class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
BGA 跑分台:收敛快但怕离散坑
在 BGA 测试台上,每组函数均跑满 10000 次调用。Hilly 函数在 5/25/500 维度下得分分别为 0.99992 / 0.99484 / 0.50483;Forest 函数为 1.00000 / 0.99975 / 0.32054;Megacity 离散函数则为 0.90667 / 0.96400 / 0.23035。三项合计总分 6.921,折算百分比 76.90%,在 31 个对比算法里排第一。 可视化过程显示种群高度收敛,但有趣的是总有一小撮个体漂在全局极值远处,说明算法仍在探未知区、维持了解多样性。不过 Megacity 这种离散函数让 BGA 也吃了瘪——500 维只拿到 0.23 水平,大多数演化类算法在这上面都翻车。 横向看榜单:排第二的 (P+O)ES 总分 6.496(72.18%),SDSm 5.709(63.44%),DE 差分进化仅 4.955(55.06%)。BGA 在 Hilly 和 Forest 上几乎碾压,Megacity 上虽掉链子但仍优于其它对手。 外汇与贵金属参数优化属高风险操作,回测高分不预示实盘概率优势。开 MT5 把上述维度组合丢进遗传优化器,先验证 Hilly 类连续函数能否复现 0.99+ 收敛,再掂量离散品种该怎么降维。
◍ 别急着下结论
BGA 作为经典 GA 的二进制特例,把独立维度压进一条染色体统一编码,这种结构在实值编码里很难复刻,也让它在平滑、离散乃至大规模随机问题上都跑得动。实验里相关测试分值 ≥0.99 的结果会用白色高亮,直方图标尺 0–100 且越大越好,100 仅是理论极值,别拿它当实盘预期。 交叠算子像摇万花筒:随机切分染色体再拼回,可能把不同解元的好特征揉成更优组合,但结果也可能偏得出奇,不是每次都出钻石。它优势在抗粘连和高收敛,短板是外部参数多、实现复杂、算力吃紧,外汇与贵金属优化属高风险,回测亮眼不代表实盘能复现。 附档 31_The_world_of_AO_BGA.zip(约 567.93 KB)含前几篇算法代码的更新版,作者声明多处改动只为提升搜索力,结论基于实验而非绝对规范。开 MT5 把脚本挂上跑一遍,比盯着文字琢磨更实在。