种群优化算法:鱼群搜索(FSS)(基础篇)
📘

种群优化算法:鱼群搜索(FSS)(基础篇)

第 1/2 篇

「鱼群搜索在 MT5 里的种群优化思路」

鱼群搜索(FSS)属于种群优化算法的一种,在 MT5 中常被用来替代网格遍历,去搜参数空间里更优的 EA 配置。它模拟鱼群觅食时的个体移动、聚群和追尾行为,靠群体随机试探逐步逼近低回撤、高夏普的解。 原文示例发布于 2023 年 4 月 27 日,在 MetaTrader 5 板块下获得 1352 次查看、4 条讨论,作者 Andrey Dik 将其拆为概述、算法描述、测试结果三块来写。 对外汇与贵金属 EA 做种群优化,本质上是在高杠杆、高波动环境里找稳健参数;这类品种风险极高,回测漂亮不代表实盘能复现,开 MT5 用策略测试器跑一遍自己的品种才能确认。

◍ 鱼群聚集与群体智慧的数学雏形

鱼群并非随机堆砌,而是分结构化与非结构化两类。非结构化聚集多为混种、混尺寸,因局部食物或巢址临时凑堆;一旦同周期、同物种个体开始社会式互动,便升级为具备组织活性的团体,在抗捕食与争食间取得折衷。 自然界鱼群倾向由外貌雷同的本种个体组成较大团体——形差者会成为捕食者首要目标,这驱动了整个团体的同质化。当同速同向同步游动时,组织最严:同物种、同年龄层、保持定距,能做出似有共同头脑的复杂机动,如细长方阵中快速升降、绕轴旋转且互不碰撞,依赖极快的相对位置感应与响应。 数学建模把这种行为压成三条基本规则:与邻同速同向、与邻保持近距离、避免与邻碰撞。但团体游弋方向由谁定仍未解,迁移中似多数知情,小群中仍有更大胆的领导者。该行为已催生出解决优化问题的算法模型,值得在 MT5 里用群体逻辑跑一遍参数敏感性。 外汇与贵金属属高风险市场,任何借群体算法做的信号辅助都只具概率倾向,不能直接当方向凭据。

鱼群搜索怎么在MT5里落地

鱼群搜索(FSS)归在群体智能里的元启发式一类,2008年由 Bastos Filho 和 Lima Neto 提出,核心代理叫“鱼”,每条鱼带一个权重记录寻优“成功度”。权重同时充当记忆,这让 FSS 跟粒子群不同——它不需要显式维护全局最优,靠权重中心在迭代里自然漂移到更优点。 算法算子分两组:投喂算子算权重,游泳算子管迁移。投喂里权重增量正比于归一化适应度差:fishes[f].weight = fishes[f].weight + (fishes[f].delta_fitness / max_delta_fitness)。游泳又拆成个体、本能集体、集体意志三类,个体游弋是局部随机步,本能集体按上轮适应度变化同步平移鱼群,集体意志则看团体是否改善决定向质心聚或散。 原文作者把伪代码接进 MT5 时改了调用顺序:经典是个体→算适应度→本能→意志,但他用 Init 和 swimmingRegime 两个标志重排成 first_method→算适应度→second_method。Init() 里鱼结构清零,权重预设 1000.0,适应度填 -DBL_MAX,这样首轮差值为零。 步长参数他没照文献的 0.01 / 0.001,实测不好用,改成 initial_step_ind=0.1、initial_step_vol=0.8。喂养里若 max_delta_fitness 为零,他允许权重取负、直接令 weight=1,不强制适应度必须为正。开 MT5 把下面结构跑一遍,看权重中心是否随迭代往高适应度区挪。

MQL5 / C++
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="kw">struct S_Fish
{
  class="type">void Init(class="type">int dimensions)
  {
    ArrayResize(current_position, dimensions);
    ArrayResize(new_position,     dimensions);
    ArrayResize(delta_position,   dimensions);
    weight        = class="num">1000.0;
    fitness       = -DBL_MAX;
    delta_fitness = class="num">0.0;
  }

「鱼群算法初始化与游泳调度的落地细节」

下面这段是鱼群搜索(FSS)类里最容易被忽略的两段代码:Init 负责把维度、鱼群规模、步长系数一次性落进数组;Swimming 则按 init 标志决定是冷启动随机撒点,还是进入个体/群体移动 regime。直接在 MT5 里建个 EA 把这两段粘进去,用 Print 打出 step_ind[0] 和 global_best,能立刻看到第一帧的搜索边界。 Init 的前几行先用 MathSrand(GetTickCount()) 播种随机,保证每次 EA 重启后鱼群初始分布不重复;随后把 dimensions、fishSchSizeP 写进成员变量,并用 ArrayResize 给 rangeMax / rangeMin / rangeStep / fishes 按维度或规模扩容。注意 total_weight 直接赋成 num_of_individuos,意味着初始阶段每条鱼权重相等,后续 volitive 移动才会按 fitness 重新分配。 Swimming 的冷启动分支里,step_ind[d] 和 step_vol[d] 都等于初始系数乘上该维搜索跨度 (rangeMax[d]-rangeMin[d]);鱼的位置 new_position[d] 先由 RNDfromCI 在连续区间随机,再经 SeInDiSp 吸附到离散网格——如果你的参数空间是手数或均线周期这类整数维,这步能避免浮点越界。 当 init 为 true 后,swimmingRegime==1 只跑个体移动,其余情况走本能集体移动+意志集体移动两段。实盘调参时建议先把 swimmingRegime 锁在 1,单看个体移动能否在 200 代内把 fitness 拉出 -DBL_MAX,再放开群体项,外汇与贵金属波动剧烈,此类优化仅作信号参考,实盘存在较高风险。

MQL5 / C++
class="type">class="kw">double current_position [];
class="type">class="kw">double new_position     [];
class="type">class="kw">double delta_position   [];
class="type">class="kw">double weight;
class="type">class="kw">double fitness;
class="type">class="kw">double new_fitness;
class="type">class="kw">double delta_fitness;
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_FSS::Init(class="kw">const class="type">int     dimensionsP,
                     class="kw">const class="type">int     fishSchSizeP,
                     class="kw">const class="type">class="kw">double initial_step_indP,
                     class="kw">const class="type">class="kw">double initial_step_volP)
{
  MathSrand(GetTickCount());
  init = class="kw">false;
  swimmingRegime = class="num">1;
  dimensions      = dimensionsP;
  ArrayResize(rangeMax,  dimensions);
  ArrayResize(rangeMin,  dimensions);
  ArrayResize(rangeStep, dimensions);
  num_of_individuos = fishSchSizeP;
  ArrayResize(fishes, num_of_individuos);
  for (class="type">int i = class="num">0; i < num_of_individuos; i++)
  {
    fishes [i].Init(dimensions);
  }
  global_best = -DBL_MAX;
  ArrayResize(global_best_position, dimensions);
  total_weight      = num_of_individuos;
  initial_step_ind = initial_step_indP;
  ArrayResize(step_ind, dimensions);
  initial_step_vol = initial_step_volP;
  ArrayResize(step_vol, dimensions);
  ArrayResize(collective_instinct, dimensions);
  ArrayResize(barycenter, dimensions);
}
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">void C_AO_FSS::Swimming(class="type">int i)
{
  class=class="str">"cmt">//----------------------------------------------------------------------------
  if (!init)
  {
    global_best      = -DBL_MAX;
    swimmingRegime = class="num">1;
    for (class="type">int d = class="num">0; d < dimensions; d++)
    {
      step_ind [d] = initial_step_ind * (rangeMax [d] - rangeMin [d]);
      step_vol [d] = initial_step_vol * (rangeMax [d] - rangeMin [d]);
    }
    for (class="type">int f = class="num">0; f < num_of_individuos; f++)
    {
      fishes [f].Init(dimensions);
      for (class="type">int d = class="num">0; d < dimensions; d++)
      {
        fishes [f].new_position [d] = RNDfromCI(rangeMin [d], rangeMax [d]);
        fishes [f].new_position [d] = SeInDiSp(fishes [f].new_position [d], rangeMin [d], rangeMax [d], rangeStep [d]);
      }
    }
  }
  class=class="str">"cmt">//----------------------------------------------------------------------------
  else
  {
    class="kw">switch (swimmingRegime)
    {
    case class="num">1:
      apply_individual_movement();                    class=class="str">"cmt">//individual movement
      class="kw">break;
    class="kw">default:
      apply_instintive_collective_movement(); class=class="str">"cmt">//instinctively-collective movement
      apply_collective_volitive_movement();   class=class="str">"cmt">//collective-volitional movement

常见问题

每条鱼按自身历史最佳和群体最佳位置更新移动,靠聚集、随机游动和追随来逼近最优解,本质是群体智慧的迭代搜索。
先限定参数搜索区间,鱼群数量取20~50条,迭代代数控制在100代内,避免过早收敛或计算过久。
小布可接入你的策略文件,自动按鱼群思路搜索最优参数组合并给出对比报告,你只需确认区间和指标。
个体步长取搜索域的1%~5%,聚集步长略小于个体步长,实盘前用历史数据回测微调可降低过拟合。
维度超3个时鱼群通常比网格快数倍,但需多跑几次防陷局部最优,贵金属等高波动品种建议分段优化。