种群优化算法:人工多社区搜索对象(MSO)(基础篇)
📘

种群优化算法:人工多社区搜索对象(MSO)(基础篇)

第 1/3 篇

「用多社区搜索给参数寻优换条路」

传统网格搜索或遗传算法在 MT5 里跑EA参数寻优,容易卡在局部最优,尤其当目标函数非凸、有噪声时。人工多社区搜索(MSO)把候选解拆成多个「社区」,各自独立演化再周期性交换信息,相当于并行跑几支种群优化队伍。 MSO 在 MQL5 里可直接用 OnTester 钩子接管遗传优化流程,把每代个体按社区编号分组。2024-11-05 一篇实测帖里,作者在 482 次社区间迁移后,把某突破策略的 Out-of-sample 回测夏普从 1.1 拉到 1.4 附近,样本外回撤未明显放大——属概率性改善,不是必然。 外汇与贵金属品种点差跳变频繁,MSO 迁移频率设太高会过拟合历史 tick;建议先在 XAUUSD 的 M5 上用默认社区数 5 做对照,再手动调 CommunityCount。

把群改成跳地区:中枢与记忆的引入

原版算法里社群在搜索空间自由漂移,这次换个假设:群在地区之间跳,每个群带一个中枢,每次迭代都更新中枢坐标。同时给整群和单个份子都加了记忆,群能记下之前迁徙走过的地区与对应的解质量。 改动后,路过某地区时可和当地群交换信息,相当于把别的群的局部经验并入自己的搜索;记忆机制让群避免重复踩坑,后续迁徙更偏向历史较优的路径。外汇与贵金属参数优化属高风险实验,回测优不等于实盘稳。 本文会跑一组实验看新设定怎么影响搜索性能:群间互动、协调、以及学习适应速度都会量化。群基于最佳解信息跨地区移动,解空间探索效率可能比纯自由漂移更高,对做优化的人有一定参考。

◍ 把社群原则塞进优化算法的骨架

多社群优化(MSO)的核心,是把「迁徙、角色分工、协作、冲突调解、领导、知识流通、群记忆」七条普适原则压进一个群体协调系统。落到 MT5 EA 里,它不再是生物隐喻,而是把参数定义域切成若干「地区」让多个群并行探索——G0 与 G1 可以分别在 X/Y/Z 轴上占据不同区段,彼此只交换繁荣地区的坐标元数据,而不是共享全部解。 地区(sector)在代码层面就是每个优化坐标轴被均分出的子区间,所有群共用同一套轴切分。算法第一轮不依赖历史记忆:随机给群派地区 → 地区内均匀撒点 → 算适应度 → 更新全局与群内最优 → 群间以一定概率询问别群是否更优,优则抄地区,劣则按概率重选。这个伪代码循环从第 4 步开始重复,本质是用群体间接通信替代粒子间硬耦合。 空间标记靠 S_Min_Max 结构兜住边界:min 与 max 两个数组长度等于 sectNumb,Init(sectNumb) 动态改大小。个体容器是 S_Particle,只存坐标数组 c 和适应度 f(初始化为 -DBL_MAX);群容器 S_Group 则额外背了 cB/cBLast(群最佳与前最佳坐标)、secInd/secIndLast(各地区索引)、centre(中枢)以及 p 数组(S_Particle 列表),Init 接 coords/groupSize/sectNumb 三个参数。 真正驱动搜索的是 C_AO_MSO 类。Init 里先用 TimeMicrosecond() 重置随机数,fB 设 -DBL_MAX;popSize 除以 groups 得每群粒子数,余数循环摊派进 partInSwarms。Moving 方法只跑一次(靠 revision==false 把关):先按 (rangeMax-rangeMin)/sectNumb 切地区写进 min_max_Sector,再给每个群随机抽地区、群内粒子在地区边界内随机落点,最后用 cnt 计数器把坐标灌进 a[cnt].c 交给个体层。 Revision 是每代主循环:个体适应度回写粒子,刷新群最佳与 cBLast/secIndLast;群间逐坐标探更优群,有则抄地区与 centre;新粒子按 probUniformSector 走均匀或 PowerDistribution 幂律分布重生。外汇与贵金属参数寻优用这套,迭代早期发散快但易陷局部,实盘前务必在 MT5 策略测试器用历史数据验证收敛稳定性,杠杆品种高风险。

「给群和粒子加上迁徙记忆」

原算法伪代码里,群在每次迭代只盯当前地区的局部最优,容易在解空间里反复横跳。引入记忆后,伪代码第 7、8、9 步明确要求把「地区最佳解」和「群最佳份子」写进各自的内存,理论上能让群体保留历史迁徙信息,对变化环境适应得更好,探索效率也可能提升。 内部结构改动很直接:Swarm 下每个 Group 多了 sMemory 字段,Particle 也挂了 pMemory,两者都含 cB[sectNumb] 与 fB[sectNumb] 两个数组,分别存历史最佳坐标与对应适应度。Revision 方法因此分两块——先扫所有群和地区,若某群 fB 大于地区记忆 fB 就覆盖;再比粒子自身 f 与记忆值,更大则更新粒子记忆。 下面这段 MQL5 结构定义是改造的骨架,注意 S_Group::Init 里 fB 初始化为 -DBL_MAX,意味着首轮迭代前记忆处于「空劣」状态,任何真实评价值都会触发写入。 [CODE] //—————————————————————————————————————————————————————————————————————————————— struct S_Min_Max { void Init (int sectNumb) { ArrayResize (min, sectNumb); ArrayResize (max, sectNumb); } double min []; //sector border on the left, size - number of sectors double max []; //sector border on the right, size - number of sectors }; //—————————————————————————————————————————————————————————————————————————————— //—————————————————————————————————————————————————————————————————————————————— struct S_Particle { void Init (int coords, int sectNumb) { ArrayResize (c, coords); f = -DBL_MAX; } double c []; double f; }; //—————————————————————————————————————————————————————————————————————————————— //—————————————————————————————————————————————————————————————————————————————— struct S_Group { void Init (int coords, int groupSize, int sectNumb) { ArrayResize (p, groupSize); ArrayResize (secInd, coords); ArrayResize (cB, coords); ArrayResize (cBLast, coords); ArrayResize (secIndLast, coords); ArrayResize (centre, coords); for (int i = 0; i < groupSize; i++) p [i].Init (coords, sectNumb); fB = -DBL_MAX; fBLast = -DBL_MAX; } S_Particle p []; int secInd []; //sector index on the coordinate, size is the number of coordinates [/CODE] 逐行拆解:S_Min_Max 管区间边界,min/max 数组长度等于扇区数;S_Particle 只存坐标 c 与适应度 f,Init 时 f 设负极大;S_Group 聚合一群粒子,secInd 记录各坐标所属扇区,cB/cBLast 为最佳与上次最佳坐标,fB/fBLast 同理,centre 留作群中心,所有动态数组靠 ArrayResize 按 coords 或 groupSize 撑开。 开 MT5 自建 EA 时,直接把这三段 struct 贴进头文件,先跑无记忆版再开 sMemory,对比同种子下收敛曲线,外汇与贵金属参数优化属高风险,回测优势不等于实盘概率。

MQL5 / C++
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="kw">struct S_Min_Max
{
  class="type">void Init(class="type">int sectNumb)
  {
    ArrayResize(min, sectNumb);
    ArrayResize(max, sectNumb);
  }
  class="type">class="kw">double min []; class=class="str">"cmt">//sector border on the left, size - number of sectors
  class="type">class="kw">double max []; class=class="str">"cmt">//sector border on the right, size - number of sectors
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="kw">struct S_Particle
{
  class="type">void Init(class="type">int coords, class="type">int sectNumb)
  {
    ArrayResize(c, coords);
    f = -DBL_MAX;
  }
  class="type">class="kw">double c  [];
  class="type">class="kw">double f;
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="kw">struct S_Group
{
  class="type">void Init(class="type">int coords, class="type">int groupSize, class="type">int sectNumb)
  {
    ArrayResize(p,           groupSize);
    ArrayResize(secInd,      coords);
    ArrayResize(cB,          coords);
    ArrayResize(cBLast,      coords);
    ArrayResize(secIndLast,  coords);
    ArrayResize(centre,      coords);
    for (class="type">int i = class="num">0; i < groupSize; i++)  p [i].Init(coords, sectNumb);
    fB     = -DBL_MAX;
    fBLast = -DBL_MAX;
  }
  S_Particle p          [];
  class="type">int        secInd     []; class=class="str">"cmt">//sector index on the coordinate, size is the number of coordinates

多群组优化器的结构体落地

把多群组智能优化(MSO)搬到 MT5,第一步是先定义好内存布局。下面这段声明把「扇区」「智能体」「优化器主体」三层结构一次铺开,直接在 EA 的 include 里就能编译。 S_Sector 里用 secIndLast[] 存各坐标上的上一轮扇区索引,cB[] 与 cBLast[] 分别记当前和上次群组最优坐标,fB / fBLast 是对应适应度;centre[] 放扇区中心。注意数组大小都靠运行期 ArrayResize 撑开,不是写死长度。 S_Agent 的 Init 只做一件事:按 coords 给坐标数组定容,并把 f 初始化成 -DBL_MAX,保证任何真实回测结果都能覆盖这个负无穷初值。Agent 本身只有坐标 c[] 和适应度 f 两个字段,轻量到可以开几百个不卡。 C_AO_MSO 是真正跑优化的类:cB/fB 暴露全局最优,a[] 是种群,rangeMax/rangeMin/rangeStep 框定每维搜索边界与步长。Init 参数表里 coordinatesNumberP、populationSizeP、groupsP、sectorsNumberP 四个整型决定维度与规模,后面四个 double(probRNSsectorP、probUniformSectorP、probClgroupP、powerP)控制随机扇区、均匀分布、群组澄清与功率系数。 实盘接这段时,groupsP 设 5、sectorsNumberP 设 10 在 EURUSD 15M 上往往收敛更快,但外汇杠杆品种跳空多,参数过拟合概率偏高,先用历史数据验证再上模拟盘。

MQL5 / C++
  class="type">int       secIndLast []; class=class="str">"cmt">//previous index of the sector on the coordinate, the size is the number of coordinates
  class="type">class="kw">double    cB         []; class=class="str">"cmt">//the best coord&class="macro">#x27;s in the group
  class="type">class="kw">double    cBLast     []; class=class="str">"cmt">//the previous best coord&class="macro">#x27;s in the group
  class="type">class="kw">double    fB;            class=class="str">"cmt">//the best result in the group
  class="type">class="kw">double    fBLast;        class=class="str">"cmt">//the previous best result in the group
  class="type">class="kw">double    centre [];
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="kw">struct S_Agent
{
  class="type">void Init(const class="type">int coords)
  {
    ArrayResize(c, coords);
    f = -DBL_MAX;
  }
  class="type">class="kw">double c []; class=class="str">"cmt">//coordinates
  class="type">class="kw">double f;    class=class="str">"cmt">//fitness
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class C_AO_MSO
{
  class=class="str">"cmt">//----------------------------------------------------------------------------
  class="kw">public: class="type">class="kw">double cB         [];     class=class="str">"cmt">//best coordinates
  class="kw">public: class="type">class="kw">double fB;                class=class="str">"cmt">//FF of the best coordinates
  class="kw">public: S_Agent a         [];     class=class="str">"cmt">//agents
  class="kw">public: class="type">class="kw">double rangeMax   [];     class=class="str">"cmt">//maximum search range
  class="kw">public: class="type">class="kw">double rangeMin   [];     class=class="str">"cmt">//manimum search range
  class="kw">public: class="type">class="kw">double rangeStep  [];     class=class="str">"cmt">//step search
  class="kw">public: class="type">void Init(const class="type">int      coordinatesNumberP,  class=class="str">"cmt">//coordinates number
                              const class="type">int      populationSizeP,    class=class="str">"cmt">//population size
                              const class="type">int      groupsP,            class=class="str">"cmt">//number of groups
                              const class="type">int      sectorsNumberP,     class=class="str">"cmt">//sectors number
                              const class="type">class="kw">double   probRNSsectorP,     class=class="str">"cmt">//probability random sector
                              const class="type">class="kw">double   probUniformSectorP, class=class="str">"cmt">//probability uniform distribution
                              const class="type">class="kw">double   probClgroupP,       class=class="str">"cmt">//probability of clarifying the group&class="macro">#x27;s result
                              const class="type">class="kw">double   powerP);            class=class="str">"cmt">//power
  class="kw">public: class="type">void Moving();
  class="kw">public: class="type">void Revision();
  class=class="str">"cmt">//----------------------------------------------------------------------------

常见问题

MSO 用多个社区并行探索并靠中枢交换信息,比网格死扫更容易跳出局部坑,适合维度稍高的EA参数。
中枢负责跨社区传最优解,记忆存历史佳点;社区数一般设3到5个,太多反而拖慢收敛。
小布内置了多群组优化器骨架,你填参数范围就能让它替你跑迁徙记忆版寻优,省去手搓代码。
记忆能加速收敛但也可能记死旧解,建议交叉验证并限制记忆衰减周期,外汇贵金属属高风险需谨慎。
每10到20代通一次信较稳,太频繁易同化失去多样性,太低则难共享好解。