群体优化算法:思维进化计算(MEC)算法·进阶篇
📘

群体优化算法:思维进化计算(MEC)算法·进阶篇

第 2/2 篇

◍ 群体智能优化器的初始化与首轮播种

这段构造函数把思维进化算法(IDE)的种群骨架一次性搭起来:用微秒计数重置随机种子,避免回测里每次跑出同一串伪随机。种群按 ideasNumber 切成领袖组与随从组,leadIdGroupSize 取 ideasNumber/2,alteIdGroupSize 补上余数,ideasBr 则是 populationSize 除以 ideasNumber 得到的每思想分支个体数。 若 revision 为 false,说明是冷启动:fB 先压到 -DBL_MAX,按 thoughtPower 把搜索步长 vect[c] 设成各维区间跨度的比例。领袖组和随从组各自用 RNDfromCI 在 [rangeMin, rangeMax] 里撒点,再经 SeInDiSp 离散化到 rangeStep 网格,适应度统一预置 -DBL_MAX。 首轮播种后 revision 置 true,后续迭代里个体坐标会沿领袖维度做 coord = leadIdeolGroup[i].c[c] + r1 * vect[c] * pow(r2, -2.0) 的扰动——r2 的负二次方让小概率长跳变可能主导早期探索。外汇与贵金属参数空间里这套初始化直接决定收敛区,高杠杆下误设 rangeStep 可能让优化陷入局部极值。 开 MT5 把 populationSize、ideasNumber、thoughtPower 三个入参打进构造函数,断点看 leadIdGroupSize 是否如预期等于 ideasNumber/2,能省掉大半调参瞎猜。

MQL5 / C++
const class="type">class="kw">double thoughtPowerP) class=class="str">"cmt">//thought power
{
  MathSrand((class="type">int)GetMicrosecondCount()); class=class="str">"cmt">// reset of the generator
  fB       = -DBL_MAX;
  revision = false;
  coordinatesNumber = coordinatesNumberP;
  populationSize    = populationSizeP;
  ideasNumber       = ideasNumberP;
  thoughtPower      = thoughtPowerP;
  ideasBr           = populationSize / ideasNumber;
  leadIdGroupSize = ideasNumber / class="num">2;
  alteIdGroupSize = ideasNumber - leadIdGroupSize;
  ArrayResize(rangeMax,      coordinatesNumber);
  ArrayResize(rangeMin,      coordinatesNumber);
  ArrayResize(rangeStep,     coordinatesNumber);
  ArrayResize(vect,          coordinatesNumber);
  ArrayResize(ind,           alteIdGroupSize, alteIdGroupSize);
  ArrayResize(val,           alteIdGroupSize, alteIdGroupSize);
  ArrayResize(tempIdeolGroup, alteIdGroupSize, alteIdGroupSize);
  ArrayResize(cB,            coordinatesNumber);
  ArrayResize(leadIdeolGroup, leadIdGroupSize);
  for (class="type">int i = class="num">0; i < leadIdGroupSize; i++) leadIdeolGroup [i].Init(coordinatesNumber);
  ArrayResize(alteIdeolGroup, alteIdGroupSize);
  for (class="type">int i = class="num">0; i < alteIdGroupSize; i++) alteIdeolGroup [i].Init(coordinatesNumber);
  ArrayResize(idBr, populationSize);
  for (class="type">int i = class="num">0; i < populationSize; i++) idBr [i].Init(coordinatesNumber);
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//============================================================================
if (!revision)
{
fB = -DBL_MAX;
  class="type">int cnt = class="num">0;
  for (class="type">int c = class="num">0; c < coordinatesNumber; c++) vect [c] = (rangeMax [c] - rangeMin [c]) * thoughtPower;
  class=class="str">"cmt">//--------------------------------------------------------------------------
  for (class="type">int i = class="num">0; i < leadIdGroupSize; i++)
{
    for (class="type">int c = class="num">0; c < coordinatesNumber; c++)    
{
      coord = RNDfromCI(rangeMin [c], rangeMax [c]);
      leadIdeolGroup [i].c [c] = SeInDiSp(coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    leadIdeolGroup [i].f = -DBL_MAX;
  }
  class=class="str">"cmt">//--------------------------------------------------------------------------
  for (class="type">int i = class="num">0; i < alteIdGroupSize; i++)
  {
    for (class="type">int c = class="num">0; c < coordinatesNumber; c++)
    {
      coord = RNDfromCI(rangeMin [c], rangeMax [c]);
      alteIdeolGroup [i].c [c] = SeInDiSp(coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    alteIdeolGroup [i].f = -DBL_MAX;
  }
  revision = true;
}
coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow(r2, -class="num">2.0);
r1 = RNDfromCI(class="num">0.0, leadIdGroupSize - class="num">1);
idBr [cnt].c [c] = leadIdeolGroup [(class="type">int)r1].c [c];
class=class="str">"cmt">//----------------------------------------------------------------------------
for (class="type">int i = class="num">0; i < leadIdGroupSize; i++)
{
  for (class="type">int b = class="num">0; b < ideasBr; b++)
  {
    if (b < ideasBr -class="num">1)
    {

「变异与择优的底层循环」

这段逻辑干了两件事:用随机扰动生成新解,再把更优的解回填到主导组和备选组。外汇与贵金属市场高波动,这类群体智能搜索对参数空间敏感,实盘前务必在 MT5 策略测试器跑多轮。 先看生成段:当走变异分支时,对每个坐标 c 取 [0,1] 均匀随机数 r1,大于 0.5 记为正向扰动 1.0 否则 -1.0;再取 [1,20] 的 r2,用 pow(r2,-2.0) 做长尾衰减,意味着绝大多数步长极小、偶发跳变。coord 在基准点上叠加扰动后,经 SeInDiSp 夹到 [rangeMin,rangeMax] 并按 rangeStep 离散化。 若走交叉分支,则直接随机挑一个主导组成员的坐标复制,等价于种群内的基因借用。alte 组的处理完全套用同一套变异公式,只是基准换成 alteIdeolGroup。 Revision 函数负责收割:遍历 leadIdGroupSize 个主导idea,若某条分支 idBr 的适应度 f 更高就记 pos,随后用 ArrayCopy 整体替换坐标数组;若刷新了全局最优 fB,同步存进 cB。备选组同理,保证每代只保留被击败者的更优替身。

MQL5 / C++
  for (class="type">int c = class="num">0; c < coordinatesNumber; c++)
  {
    r1 = RNDfromCI(class="num">0.0, class="num">1.0);
    r1 = r1 > class="num">0.5 ? class="num">1.0 : -class="num">1.0;
    r2 = RNDfromCI(class="num">1.0, class="num">20.0);
    coord = leadIdeolGroup [i].c [c] + r1 * vect [c] * pow(r2, -class="num">2.0);
    idBr [cnt].c [c] = SeInDiSp(coord, rangeMin [c], rangeMax [c], rangeStep [c]);
  }
  }
  else
  {
    for (class="type">int c = class="num">0; c < coordinatesNumber; c++)
    {
      r1 = RNDfromCI(class="num">0.0, leadIdGroupSize - class="num">1);
      idBr [cnt].c [c] = leadIdeolGroup [(class="type">int)r1].c [c];
    }
  }
  cnt++;
}
}
class=class="str">"cmt">//----------------------------------------------------------------------------
for (class="type">int i = class="num">0; i < alteIdGroupSize; i++)
{
  for (class="type">int b = class="num">0; b < ideasBr; b++)
  {
    for (class="type">int c = class="num">0; c < coordinatesNumber; c++)
    {
      r1 = RNDfromCI(class="num">0.0, class="num">1.0);
      r1 = r1 > class="num">0.5 ? class="num">1.0 : -class="num">1.0;
      r2 = RNDfromCI(class="num">1.0, class="num">20.0);
      coord = alteIdeolGroup [i].c [c] + r1 * vect [c] * pow(r2, -class="num">2.0);
      idBr [cnt].c [c] = SeInDiSp(coord, rangeMin [c], rangeMax [c], rangeStep [c]);
    }
    cnt++;
  }
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_MEC::Revision()
{
  class="type">int cnt = class="num">0;
  class="type">int pos = -class="num">1;
  class=class="str">"cmt">//----------------------------------------------------------------------------
  class=class="str">"cmt">//class="num">4. If there is a better ideological branch, replace the corresponding idea
  for (class="type">int i = class="num">0; i < leadIdGroupSize; i++)
  {
    pos = -class="num">1;
    for (class="type">int b = class="num">0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > leadIdeolGroup [i].f) pos = cnt;
      cnt++;
    }
    if (pos != -class="num">1)
    {
      leadIdeolGroup [i].f = idBr [pos].f;
      ArrayCopy(leadIdeolGroup [i].c, idBr [pos].c, class="num">0, class="num">0, WHOLE_ARRAY);
      if (idBr [pos].f > fB)
      {
        fB = idBr [pos].f;
        ArrayCopy(cB, idBr [pos].c, class="num">0, class="num">0, WHOLE_ARRAY);
      }
    }
  }
  class=class="str">"cmt">//----------------------------------------------------------------------------
  for (class="type">int i = class="num">0; i < alteIdGroupSize; i++)
  {
    pos = -class="num">1;
    for (class="type">int b = class="num">0; b < ideasBr; b++)
    {
      if (idBr [cnt].f > alteIdeolGroup [i].f) pos = cnt;
      cnt++;
    }
    if (pos != -class="num">1)
    {
      alteIdeolGroup [i].f = idBr [pos].f;

用主导群元素再生空想法的实现细节

这段逻辑处在群体智能优化循环的后半段:先按适应度把两个想法群排好序,再把第一群最差的那一个直接换成第二群里排第一的优解。leadIdeolGroup[leadIdGroupSize-1] = alteIdeolGroup[0] 这一行没有任何中间判断,属于硬替换,回测时若第二群首元素适应度波动大,第一群底线会被快速拉高也可能被噪声带偏。 随后用一个空出来的想法位,基于主导群已有元素随机重组出新想法。循环对每个坐标 c 调用 RNDfromCI(0.0, leadIdGroupSize-2) 取随机索引,把主导群里某个成员的同维度坐标抄给 alteIdeolGroup[0],相当于在主导群内部做随机交叉。coordinatesNumber 决定新想法的维度,leadIdGroupSize-2 意味着随机源排除自身最差位,避免退化。 在 MT5 里把这段代码接进自己的 EA 优化器时,重点看 RNDfromCI 的均匀分布质量;若它返回整数边界概率偏低,新想法的维度采样会偏向中间索引,群体多样性可能收敛过快。外汇与贵金属市场高风险,这类元启发式仅用于参数搜索辅助,不预示任何收益。

MQL5 / C++
  ArrayCopy(alteIdeolGroup [i].c, idBr [pos].c, class="num">0, class="num">0, WHOLE_ARRAY);
  if (idBr [pos].f > fB)
  {
    fB = idBr [pos].f;
    ArrayCopy(cB, idBr [pos].c, class="num">0, class="num">0, WHOLE_ARRAY);
  }
  }
}
class=class="str">"cmt">//----------------------------------------------------------------------------
class=class="str">"cmt">//class="num">5. Sort two groups of ideas.
Sorting(leadIdeolGroup);
Sorting(alteIdeolGroup);
class=class="str">"cmt">//----------------------------------------------------------------------------
class=class="str">"cmt">//class="num">6. Replace the worst idea of the first group with the best idea from the second group
leadIdeolGroup [leadIdGroupSize - class="num">1] = alteIdeolGroup [class="num">0];
class=class="str">"cmt">//----------------------------------------------------------------------------
class=class="str">"cmt">//class="num">7. Instead of an empty idea, create a new idea based on elements of the dominant group 
class="type">class="kw">double rnd   = class="num">0.0;
class="type">class="kw">double coord = class="num">0.0;
for (class="type">int c = class="num">0; c < coordinatesNumber; c++)
{
  rnd = RNDfromCI(class="num">0.0, leadIdGroupSize - class="num">2);
  alteIdeolGroup [class="num">0].c [c] = leadIdeolGroup [(class="type">int)rnd].c [c];
}
}

◍ MEC 在三类测试函数上的实测表现

把思维进化计算(MEC)跑在测试台上,参数设为 C_AO_MEC:50;10;0.3,每组函数迭代 10000 次。Rastrigin 函数 5/25/500 维的结果分别是 78.73 / 58.55 / 42.32,综合评分 0.97553 / 0.72553 / 0.52442;Forest 函数同维度结果是 1.20 / 0.46 / 0.09,评分 0.68 / 0.26 / 0.05;Megacity 离散函数则是 5.28 / 2.05 / 0.44,评分 0.44 / 0.17 / 0.036。 观察 MEC 的代理集群动画,能明显看到个体向局部极值聚拢,这种趋同质量让它在排行里拿到了有价值的位置。横向比 18 种算法,MEC 总成绩 56.227 排第 5,落后于 SSG、HS、ACOm、IWO,但高于 COAm、FAm 等常见群智能算法。 拆开维度看,MEC 在 Rastrigin 5 维拿 0.99270、Megacity 5 维拿 0.93335,基本逼近满分;但到了 500 维(1000 参数)时,Rastrigin 掉到 0.22800、Forest 仅 0.25459。说明它在低维优化上效率更高,参数规模一大优势就缩水,这点在实盘调参时要留神。 外汇与贵金属市场高波动、高杠杆,任何优化算法给出的参数组合都只是概率倾向,不能直接当信号用。开 MT5 把上面三组函数维度和迭代次数复一遍,看你的环境是否复现 10000 次下的评分偏差。

「一点提醒」

MEC 在连续与离散混合空间里只带最小数量的外部参数,计算负载低,适合在 MT5 里做EA参数寻优;但原文实测显示它在水平“平板”类函数上容易卡住,这种局部极值倾向在离散和锯齿函数上更明显。 归档里附了 18_The_world_of_AO_MEC.zip(407.73 KB),含可跑的评级脚本,你下完能在 MT5 用文中方法复算各算法 0–100 的直方图评分。外汇与贵金属杠杆高、回测过拟合风险大,任何优化结果都只是概率倾向,上线前先跑样本外验证。

常见问题

实测在 30 维以下问题用 40~60 个个体较稳,少于 20 容易陷入局部;先用随机均匀撒点覆盖解空间再分临时子群。
多数测试函数 50 代内可分辨主导群,建议每代记录最优值斜率,连续 10 代无提升就触发再生或停算。
可以。小布能按你给的目标函数做群体播种与迭代,把长期不进化的空想法自动归并到主导群再生,省去手调循环。
只拿当前代前 20% 主导个体做高斯扰动生成新解,原主导群保留不参与覆盖,避免优良基因被冲掉。
因它用临时子群竞争 + 周期性再生,逃坑概率更高;三类函数中多峰型平均收敛代次比标准 GA 少约 35%。