混沌优化算法(COA):续篇(基础篇)
📘

混沌优化算法(COA):续篇(基础篇)

第 1/3 篇

混沌优化算法的 MT5 实现脉络

混沌优化算法(COA)在 MetaTrader 5 中的落地,最早由 Andrey Dik 在 2026 年 4 月 23 日发布测试版本,社区初始互动量为 360 次浏览、2 条评论,说明这套思路在发布初期并未大规模扩散。 原文结构分为引言、算法实现、测试结果、总结四块,其中算法实现部分是可直接搬到 MT5 策略测试器里跑的核心。对于做价格行为研究的交易者,重点不是理论推导,而是看它怎么用混沌映射替代常规随机初值来搜参数。 外汇与贵金属市场高杠杆、高波动,任何优化算法给出的参数组合都只是历史样本上的概率倾向,实盘前必须用 MT5 自带的遗传优化做交叉验证。

◍ 混沌遍历怎么跑完三个阶段

上一节把混沌优化的来路点了一下,这一节接着把剩余方法拆开,并直接进测试函数验证。实现上它用确定性混沌去遍历解空间,而不是纯随机撒点。 核心靠三种混沌映射生成序列:逻辑映射、正弦映射、帐篷映射。它们产出的是具备伪随机性和遍历性的点列,能在不重复抽样的前提下覆盖搜索域。 算法分三段执行:先初始混沌搜索铺开候选解,再用加权梯度法做解优化,最后自适应缩圈做局部搜索。带惯性的速度向量加停滞检测,能在连续多代无改进时强制跳出,降低陷局部最优的概率。 参数动态自适应配合多种变异策略,平衡了全局探索和局部开发。外汇与贵金属品种上跑这类优化要意识到:参数空间非平稳,过拟合风险高,验证结果仅代表历史样本表现。

「混沌优化器的变异与约束处理实现」

ApplyMutation 给智能体做参数扰动时,先算变异坐标数:下限 1,上限取坐标总量的 30%,即 mutationCount = 1 + (int)(RNDprobab() * coords * 0.3)。随后把全部坐标索引打乱,循环抽取坐标做三种变异之一——完全随机、基于全局最优的相对偏移、基于混沌映射的跳变;每改完一个坐标就把速度清零,避免旧动量带偏新值。 UpdateSigma 按种群可行率调惩罚:首轮把 currentSigma 设成基础值 sigma 的一半;之后若可行解占比低于 30% 就加罚,超过 70% 就减罚,且把惩罚值钳在 [0.1*sigma, 5*sigma] 区间内。IsFeasible 则逐坐标调 CalculateConstraintValue,只要任一坐标违反值大于 eps 就判 false。 停滞治理由 ResetStagnatingAgents 负责:智能体连续 5 轮没优化就进停滞,重置概率 = 0.2 * (停滞计数 / 阈值),随机命中就调 ApplyMutation 并清零计数器。CalculateWeightedGradient 用「当前违反 / 最大违反」做权重乘梯度,违反越重调得越狠。 Moving 每轮 epoch+1,首轮只初始化种群;之后按阶段切全局/局部搜索,并定期清停滞个体。Revision 在 epoch>1 时统计改进比例来缩放 alpha:全局阶段改进低就扩搜索,局部阶段改进足就缩搜索做精修。外汇与贵金属参数优化属高风险实验,回测结论仅代表历史样本,实盘可能失效。

MQL5 / C++
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_COA_chaos::ApplyMutation(class="type">int agentIdx)
{
  class=class="str">"cmt">// Determine the number of coordinates for mutation(from class="num">1 to class="num">30% of coordinates)
  class="type">int mutationCount = class="num">1 + (class="type">int)(u.RNDprobab() * coords * class="num">0.3);
  mutationCount = MathMin(mutationCount, coords);
  class=class="str">"cmt">// Create an array of indices for mutation without repetitions
  class="type">int mutationIndices [];
  ArrayResize(mutationIndices, coords);
  class=class="str">"cmt">// Fill the array with indices
  for (class="type">int i = class="num">0; i < coords; i++)
  {
    mutationIndices [i] = i;
  }
  class=class="str">"cmt">// Shuffle the indices
  for (class="type">int i = coords - class="num">1; i > class="num">0; i--)
  {
    class="type">int j = (class="type">int)(u.RNDprobab() * (i + class="num">1));
    if (j <= i) class=class="str">"cmt">// Additional security check
    {

变异执行与惩罚因子的自适应收敛

变异阶段先把选中的坐标索引打乱顺序,再逐一对候选解施加扰动。代码里用 u.RNDprobab() 生成 0~1 的随机数 r,按阈值切出三种变异路径:r<0.3 走完全随机,r<0.6 相对全局最优 cB 做 ±10% 区间偏移,其余走混沌映射刷新 gamma 值。 每次变异后都把对应维度速度清零,再用 u.SeInDiSp() 把新值夹回 [rangeMin, rangeMax] 并按 rangeStep 离散化——这一步保证解始终合法,不会飞出参数边界。 UpdateSigma() 则管约束惩罚强度。首代给 currentSigma 设为 sigma*0.5;之后统计种群可行解比例 feasibleRatio,低于 0.3 就乘 1.2 加压,高于 0.7 就乘 0.9 放松,并把 currentSigma 限在 [sigma*0.1, sigma*5.0] 之间。 在 MT5 里把 feasibleRatio 的 0.3 / 0.7 两个拐点打印出来,能直接看到惩罚因子在第几代开始收敛;外汇与贵金属参数优化属高风险,回测可行不等于实盘稳健。

MQL5 / C++
  class="type">int temp = mutationIndices [i];
  mutationIndices [i] = mutationIndices [j];
  mutationIndices [j] = temp;
  }
}
class=class="str">"cmt">// Apply mutations to the selected coordinates
for (class="type">int m = class="num">0; m < mutationCount; m++)
{
  class="type">int c = mutationIndices [m];
  class=class="str">"cmt">// Different types of mutations for variety
  class="type">class="kw">double r = u.RNDprobab();
  class="type">class="kw">double x;
  if (r < class="num">0.3)
  {
    class=class="str">"cmt">// Complete random mutation
    x = rangeMin [c] + u.RNDprobab() * (rangeMax [c] - rangeMin [c]);
  }
  else
    if (r < class="num">0.6)
    {
      class=class="str">"cmt">// Mutation relative to global best
      class="type">class="kw">double offset = (u.RNDprobab() - class="num">0.5) * (rangeMax [c] - rangeMin [c]) * class="num">0.2;
      x = cB [c] + offset;
    }
    else
    {
      class=class="str">"cmt">// Mutation class="kw">using chaotic map
      agent [agentIdx].gamma [c] = SelectChaosMap(agent [agentIdx].gamma [c], (epochNow + c) % class="num">3);
      x = rangeMin [c] + agent [agentIdx].gamma [c] * (rangeMax [c] - rangeMin [c]);
    }
  class=class="str">"cmt">// Reset velocity
  agent [agentIdx].velocity [c] = class="num">0.0;
  class=class="str">"cmt">// Apply the new value with range check
  a [agentIdx].c [c] = u.SeInDiSp(x, rangeMin [c], rangeMax [c], rangeStep [c]);
}
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_COA_chaos::UpdateSigma()
{
  class=class="str">"cmt">// Dynamic adaptation of the penalty parameter
  class=class="str">"cmt">// Start with a small value and increase it if necessary
  if (epochNow == class="num">1)
  {
    currentSigma = sigma * class="num">0.5;
    class="kw">return;
  }
  class=class="str">"cmt">// Calculate the number of feasible solutions
  class="type">int feasibleCount = class="num">0;
  for (class="type">int i = class="num">0; i < popSize; i++)
  {
    if (IsFeasible(i))
    {
      feasibleCount++;
    }
  }
  class="type">class="kw">double feasibleRatio = (class="type">class="kw">double)feasibleCount / MathMax(class="num">1, popSize);
  class=class="str">"cmt">// Adapt the penalty parameter depending on the proportion of feasible solutions
  if (feasibleRatio < class="num">0.3)
  {
    class=class="str">"cmt">// Too few feasible solutions - increase the penalty
    currentSigma *= class="num">1.2;
  }
  else
    if (feasibleRatio > class="num">0.7)
    {
      class=class="str">"cmt">// Too many feasible solutions - reduce the penalty
      currentSigma *= class="num">0.9;
    }
  class=class="str">"cmt">// Limit the sigma value
  if (currentSigma < sigma * class="num">0.1) currentSigma = sigma * class="num">0.1;
  else
    if (currentSigma > sigma * class="num">5.0) currentSigma = sigma * class="num">5.0;
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">bool C_AO_COA_chaos::IsFeasible(class="type">int agentIdx)
{
  class=class="str">"cmt">// Check if the solution is within the feasible region
  for (class="type">int c = class="num">0; c < coords; c++)
  {

常见问题

遍历阶段通常 50~100 次迭代,搜索阶段 200~500 次,细化阶段 100 次左右;可在代码里改循环上限按需调整。
在约束处理里加惩罚因子,把违规解的目标值乘系数放大,迫使算法往可行域走;惩罚系数建议从 1e3 起调。
可以,小布能按你给的变量范围自动执行遍历、搜索、细化三阶段并回传最优参数组合,你只需复核结果。
帐篷映射遍历更均匀、易跳出局部,对数映射在边界附近更密;同一问题换映射可能收敛快慢差 20%~40%。
多是步长缩放到极小值后陷在平坦区,可设最小步长阈值或加偶发大扰动,避免过早锁死在当前解。