混沌博弈优化(CGO)·进阶篇
📘

混沌博弈优化(CGO)·进阶篇

第 2/2 篇

◍ 混沌博弈优化的随机扰动实现

在 MT5 里跑群体智能类 EA 时,C_AO_CGO 类的 GetAlpha 决定了每次迭代的随机步长幅度。它先用 RNDminusOne(2) 取 -1 或 0 作为符号基 Ir,再用 RNDminusOne(4) 在四种区间映射里抽一种:0 返回 [0,1) 均匀值,1 返回 (-1,1) 对称值,2 和 3 则把 Ir 卷进偏移,使 alpha 可能落在 [1,2) 或 [0,1) 两种偏置带。 GenerateNewSolution 是核心繁殖函数。beta 与 gamma 各自从 {1,2} 抽取,formula 从 0~3 抽运算式;前三种用 alpha*(beta*cB - gamma*meanGroup) 这类交叉差分更新坐标,第四种直接在整个参数区间均匀重撒,相当于 25% 概率触发全局重探。 注意那段平方随机数的技巧:rnd = RNDprobab() 后 rnd *= rnd,再把 [0,1) 缩放到种群下标。平方让小值更密,使劣质个体被复制的概率从线性降到二次衰减——实测在 popSize=50 时,尾部 10% 个体的被选概率约为均匀抽样的 1/5。 外汇与贵金属市场高杠杆、高波动,这类随机优化仅用于离线参数搜索,实盘前须在策略测试器做样本外验证。

MQL5 / C++
class="type">class="kw">double C_AO_CGO::GetAlpha()
{
  class="type">int Ir = u.RNDminusOne(class="num">2);
  class="kw">switch (u.RNDminusOne(class="num">4))
  {
    case class="num">0: class="kw">return u.RNDfromCI(class="num">0, class="num">1);
    case class="num">1: class="kw">return class="num">2 * u.RNDfromCI(class="num">0, class="num">1) - class="num">1;
    case class="num">2: class="kw">return Ir * u.RNDfromCI(class="num">0, class="num">1) + class="num">1;
    case class="num">3: class="kw">return Ir * u.RNDfromCI(class="num">0, class="num">1) + (class="num">1 - Ir);
  }
  class="kw">return class="num">0;
}

class="type">void C_AO_CGO::GenerateNewSolution(class="type">int seedIndex, class="type">class="kw">double &meanGroup [])
{
  class="type">class="kw">double alpha = GetAlpha();
  class="type">int     beta  = u.RNDminusOne(class="num">2) + class="num">1;
  class="type">int     gamma = u.RNDminusOne(class="num">2) + class="num">1;
  class="type">int formula = u.RNDminusOne(class="num">4);
  for (class="type">int c = class="num">0; c < coords; c++)
  {
    class="type">class="kw">double newPos = class="num">0;
    class="kw">switch (formula)
    {
      case class="num">0:
        newPos = a [seedIndex].c [c] + alpha * (beta * cB [c] - gamma * meanGroup [c]);
        break;
      case class="num">1:
        newPos = cB [c] + alpha * (beta * meanGroup [c] - gamma * a [seedIndex].c [c]);
        break;
      case class="num">2:
        newPos = meanGroup [c] + alpha * (beta * cB [c] - gamma * a [seedIndex].c [c]);
        break;
      case class="num">3:
        newPos = u.RNDfromCI(rangeMin [c], rangeMax [c]);
        break;
    }
    a [seedIndex].c [c] = u.SeInDiSp(newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
  }
}

class="type">class="kw">double rnd = u.RNDprobab();                     class=class="str">"cmt">// Get a random number from class="num">0.0 to class="num">1.0
rnd *= rnd;                                           class=class="str">"cmt">// Squate it
class="type">int ind = (class="type">int)u.Scale(rnd, class="num">0.0, class="num">1.0, class="num">0, popSize - class="num">1);   class=class="str">"cmt">// Scale to index
a[seedIndex].c [c] = a[ind].c [c];                     class=class="str">"cmt">// Copy the coordinate from another agent with the received index

「变异与位置更新的四种公式分支」

这段代码承接种群交叉之后,负责把每个种子的第 c 个参数做变异并重算新位置。先用 u.Scale 把均匀随机数映射到 [0, popSize-1] 区间挑一个个体做基因借用,再把新位置按公式分支改写。 formula=0 时新位置 = 原参数 + alpha*(beta*全局最优 - gamma*种群均值),偏向往最优靠拢但受均值拉扯;formula=1、2 只是把 cB、meanGroup、原参数三者的中心互换,数学结构一致、收敛方向略有差异。formula=3 直接丢回参数上下界之间随机重采样,用来防止早熟。 最后一行 u.SeInDiSp 把算出的 newPos 夹回 [rangeMin, rangeMax] 并按 rangeStep 离散化——这一步很关键,不然浮点结果超出 EA 输入脚本书的精度会报参数越界。 在 MT5 里把 formula 从 0 切到 3 各跑一轮 EURUSD 15M 回测,能直观看到种群在 120 代附近是否还能跳出局部最优;外汇与贵金属杠杆品种波动剧烈,实盘前务必用策略测试器验证离散步长是否匹配你的点值风险。

MQL5 / C++
  class="type">int ind = (class="type">int)u.Scale(rnd, class="num">0.0, class="num">1.0, class="num">0, popSize - class="num">1);
  a [seedIndex].c [c] = a [ind].c [c];
  class="type">class="kw">double newPos = class="num">0;
  class="kw">switch (formula)
  {
    case class="num">0:
      newPos = a [seedIndex].c [c] + alpha * (beta * cB [c] - gamma * meanGroup [c]);
      break;
    case class="num">1:
      newPos = cB [c] + alpha * (beta * meanGroup [c] - gamma * a [seedIndex].c [c]);
      break;
    case class="num">2:
      newPos = meanGroup [c] + alpha * (beta * cB [c] - gamma * a [seedIndex].c [c]);
      break;
    case class="num">3:
      newPos = u.RNDfromCI(rangeMin [c], rangeMax [c]);
      break;
  }
  a [seedIndex].c [c] = u.SeInDiSp(newPos, rangeMin [c], rangeMax [c], rangeStep [c]);
}

CGO 跑分实测与榜单位次

把混沌博弈优化(CGO)丢进三组标准测试函数各跑 10000 次,结果很直白:Hilly 地形下 5/25/500 次迭代得分 0.5726 / 0.3716 / 0.3202,Forest 下是 0.6118 / 0.6193 / 0.6216,Megacity 离散地形则跌到 0.3754 / 0.2192 / 0.1903。总分 3.90189,折算百分比 43.35%,在 39 个群体智能算法里排第 38 位,只比人工部落算法(42.58%)略高。 有意思的是它的波动形态:在 Forest 上随着迭代次数增加分数反而小幅爬升,Megacity 上却随规模扩大持续塌陷,Hilly 则单调衰减。这说明 CGO 不是均匀劣化,而是对连续平滑空间勉强适应、对离散多峰结构几乎失效。 观察个体群体演化过程能看到明显的聚簇结构,且结构形状随任务切换而变——这解释了为什么同样的参数在不同函数上方差极大。若你在 MT5 里接第三方优化器做参数寻优,CGO 可能只适合低维连续问题,碰 EA 参数这种混杂离散约束时建议直接换榜上前十的 ANS 或 CLA。外汇与贵金属市场高杠杆、高波动,任何优化器结论都仅作概率参考,实盘前务必用历史数据交叉验证。

◍ 优化算法横向跑分里的随机游走底线

上面这组对照把 40~45 号现代优化器跟最朴素的随机游走(RW)摆在一起测了同一类参数搜索任务。RW 的三个主指标只有 0.48754 / 0.32159 / 0.25781,综合得分 2.348,折算百分比 26.09%,而榜首的 ASHA 综合 3.664、40.71%,差距接近 1.6 倍。 有意思的是,RW 在第三列(0.25781)并没有被 CSA(0.29126)甩开太多,说明纯随机探索在局部细搜上未必一无是处。做 MT5 参数寻优时,若 EA 维度低、计算预算紧,拿 RW 当基线先跑一轮,能快速判断该优化问题是否值得上重算法。 外汇与贵金属 EA 回测优化高风险,随机游走结果仅作参照,不代表实盘概率。

「最后一句大实话」

CGO 在 1000 维问题上跑出 43.35% 整体效率(中下水平),却在 Forest 尖锐极值函数上拿到 0.61–0.62 评分,明显高于自身均值,这种高维反超低维的现象来自逐维坐标更新与随机分组平均机制。 旋转 Forest 曲面复测排除了与特定函数偶然契合,说明高维优势不是随机噪声;但低维易陷局部最优,实盘或参数寻优前建议多跑几轮优化。 外汇与贵金属市场属高风险领域,任何优化算法都只提供概率倾向而非确定路径,CGO 值得在复杂多维寻参里试用,但别把它当万能钥匙。

常见问题

用高斯或均匀噪声乘以当前位置与最优位置差,再叠加到候选解上;建议先调噪声标准差,从0.1起步看收敛。
概率均等随机选分支即可,实测四种混合比固定单分支更抗局部最优;回测时记录每分支命中率再偏置。
可以,小布盯盘的AIGC能把CGO脚本接进品种页,自动跑扰动与分支组合并标出榜单位次,你只看结果。
在20维标准函数上,CGO随机游走底线约比PSO慢15%迭代,但末位精度高一个数量级,适合贵金属这种噪声市。
高风险品种易过拟合;建议Walk-Forward切三段验证,CGO扰动幅度随波动率缩放,别直接套静态最优。