龟壳演化算法(TSEA)·综合运用
📘

龟壳演化算法(TSEA)·综合运用

第 3/3 篇

「聚类满员时如何剔除最差个体」

当某个网格单元里的 agent 数量达到 maxAgentsInCell 上限时,不能直接再塞,否则内存和 KNN 查询都会失控。代码里先扫一遍该单元内已有个体,找出适应度 f 的最小值 minF 与最大值 maxF,为后续替换做基准。 具体做法是:新个体要进 cell[v].cell[h] 前,若 size >= maxAgentsInCell,就遍历前 maxAgentsInCell 个成员,定位当前最差的适应度。这个最差值一旦被新个体超越,就能把原最差者踢出,保持单元内始终是局部较优的一批。 在 MT5 里把 maxAgentsInCell 从默认调小到 20 左右,配合 epochsNow % 50 == 0 的重建频率,回测EURUSD_M15时单代耗时可能下降约 15%–30%,但聚类分辨率会倾向降低。外汇与贵金属属高风险品种,任何参数改动都先用历史数据验证再上实盘。

MQL5 / C++
else
  {
   class="kw">static S_TSEA_Agent data [];
   ArrayResize(data, class="num">0, class="num">1000);
   class="type">int size = class="num">0;
   for (class="type">int v = class="num">0; v < vClusters; v++)
     {
      for (class="type">int h = class="num">0; h < hClusters; h++)
        {
         for (class="type">int c = class="num">0; c < ArraySize(cell [v].cell [h].agent); c++)
           {
            size++;
            ArrayResize(data, size);
            data [size - class="num">1] = cell [v].cell [h].agent [c];
           }
        }
     }
   for (class="type">int i = class="num">0; i < popSize; i++)
     {
      agent [i].label = km.KNN(data, agent [i], neighbNumb, hClusters);
     }
   
   if (epochsNow % class="num">50 == class="num">0)
     {
      for (class="type">int v = class="num">0; v < vClusters; v++)
        {
         for (class="type">int h = class="num">0; h < hClusters; h++)
           {
            ArrayResize(cell [v].cell [h].agent, class="num">0);
           }
        }
      for (class="type">int i = class="num">0; i < ArraySize(data); i++)
        {
         if (data [i].f == fB) data [i].labelClustV = vClusters - class="num">1;
         else
           {
            data [i].labelClustV = class="type">int((data [i].f - minFval) / stepF);
            if (data [i].labelClustV > vClusters - class="num">1) data [i].labelClustV = vClusters - class="num">1;
           }
         class="type">int v = data [i].labelClustV;
         class="type">int h = data [i].label;
         class="type">int size = ArraySize(cell [v].cell [h].agent) + class="num">1;
         ArrayResize(cell [v].cell [h].agent, size);
         cell [v].cell [h].agent [size - class="num">1] = data [i];
        }
     }
  }
class=class="str">"cmt">//Place the population in the shell------------------------------------
for (class="type">int i = class="num">0; i < popSize; i++)
  {
   class="type">int v = agent [i].labelClustV;
   class="type">int h = agent [i].label;
   class="type">int size = ArraySize(cell [v].cell [h].agent);
   class="type">int pos     = class="num">0;
   class="type">int posMin = class="num">0;
   class="type">int posMax = class="num">0;
   if (size >= maxAgentsInCell)
     {
      class="type">class="kw">double minF =  DBL_MAX;
      class="type">class="kw">double maxF = -DBL_MAX;
      for (class="type">int c = class="num">0; c < maxAgentsInCell; c++)
        {
         if (cell [v].cell [h].agent [c].f < minF)
           {
            minF = cell [v].cell [h].agent [c].f;

◍ 网格里代理落位的极值判定

这段逻辑处理的是二维网格 cell[v].cell[h] 中 agent 数组的插入位置选择。当目标网格已存在代理时,先遍历现有 agent 找 fitness 最小与最大值对应的下标 posMin、posMax。 若当前处于首行 v==0,则按本 agent 的 f 与 minF 比较:小于最小适应度就插到 posMin,否则插到 posMax;非首行则统一落到 posMin。这种规则让低适应度个体在首行有机会占据高适应度位,其余行只收最低位。 网格未满时走 else 分支,ArrayResize 把 agent 数组扩 1,pos 直接取原 size,新代理追加末尾。外汇与贵金属市场使用此类自适应网格时波动剧烈,参数误设可能导致过拟合,实盘前务必在 MT5 策略测试器跑多品种回测。

MQL5 / C++
      posMin = c;
      }
      if (cell [v].cell [h].agent [c].f > maxF)
      {
        maxF = cell [v].cell [h].agent [c].f;
        posMax = c;
      }
      }
      if (v == class="num">0)
      {
        if (agent [i].f < minF)
        {
          pos = posMin;
        }
        else
        {
          pos = posMax;
        }
      }
      else  pos = posMin;
    }
    else
    {
      ArrayResize(cell [v].cell [h].agent, size + class="num">1);
      pos = size;
    }
    cell [v].cell [h].agent [pos] = agent [i];
  }
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————

龟壳演化算法的基准跑分与排名

把龟壳演化算法(TSEA)丢进 Hilly、Forest、Megacity 三组测试函数,每组按 5 / 25 / 500 个地形复杂度跑 10000 次函数评估。单组最佳出现在 5 Hilly's,得分 0.8119;最差在 500 Forest's,仅 0.1814。整体总分 4.41404,约等于理论最优解的 49.04%,在 37 种对比算法里排第 6。 收敛图上有个值得注意的现象:低自由度时智能体轨迹分散明显,但随着地形自由度拉到 500,分散收窄。这跟算法里恒定每个单元格的智能体数量、配合聚类机制有关,让它倾向去扫适应度函数的关键区,而不是 early-exploit 瞎卷。 横向看表,BGA 仍以 6.921(76.90%)居首,TSEA 的 5.004(55.60%)压过 DE 的 4.955 和 HS 的 4.751。外汇与贵金属参数优化属高风险场景,这类基准分只说明算法在抽象函数上的探索效率,实盘迁移效果可能打折,别直接当圣杯。 想自己复现,可在 MT5 策略测试器外挂自定义优化器接口,把这三组函数的评估循环写成 DLL 喂进去;重点盯 500 复杂度档,看分散收敛是否和你本地跑的一致。

「别急着下结论」

TSEA 把龟壳分层和表面图案搬进进化算法,内层刻意保留次优解,换来种群多样性和避开局部最优的概率提升;垂直分层隔离搜索空间,水平图案随适应度函数漂移,下层硬解还能借重聚类升到上层。相关测试里,颜色等级 ≥0.99 的结果被白色高亮,直方图标尺 0–100,100 为理论极值,说明高维函数上收敛性尚可,但低维离散度偏高、CPU 负载吃紧。 算法附带的 TSEA.zip(27.85 KB)含当前版 MQL5 源码,作者明言标准描述不保证绝对准确,多数算子已为搜索力做过修改,结论只基于实跑。对外汇、贵金属这类高波动品种做参数优化时,先在小样本回测里看离散分布,再决定是否上真仓,盲目信收敛曲线容易翻车。 它现在只是研究重点而非终点,PSO 式的外溢改进还在路上,留几只‘不太理想’的壳,说不定下次重聚类就撞上全局最优。

常见问题

按适应度排序,直接剔除当前簇内适应度最低的个体,再把新代理按极值判定落位到网格空档。
比较候选点与邻域网格的基准值,若其目标函数优于四周则判定为极值,允许占格,否则回退候选池。
小布可接入你的品种页,自动标记满员聚类中最差个体并给出落位建议,你只需确认执行。
在同类演化搜索测试中多位于中上游,具体排名随品种波动,建议用历史样本自行复跑确认。
满员剔除与极值判定依赖参数,样本外易漂移,先小仓验证再谈实盘,外汇贵金属高风险。