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

群体优化算法:思维进化计算(MEC)算法(基础篇)

第 1/2 篇

用思维进化计算给 EA 找参数

思维进化计算(MEC)属于群体优化算法的一类,思路是把候选参数集当成「种群」,再按「趋同」和「异化」两步迭代逼近似优解,而不是像网格搜索那样盲目穷举。在 MT5 里跑这类算法,通常要把待优化参数挂到 EA 输入变量上,由算法框架调用回测接口评估每组参数的适应度。 原文给出的示例发布于 2024 年 5 月 27 日,社区显示浏览量 887、评论 0,作者为 Andrey Dik,全文规划为概述、算法、测试结果三块。也就是说,这一篇只是入口,真要看 MEC 在外汇或贵金属上的实际表现,得等后面测试结果那节。 如果你手头有 MT5,可以先把这篇的 EA 框架载入策略测试器,选「自定义优化」模式,感受一下群体算法和内置遗传算法的耗时差异。外汇与贵金属杠杆高、滑点扰动大,任何优化结果都只是历史样本上的概率倾向,不能直接当实盘依据。

◍ 用社会行为替代梯度下降的进化思路

进化计算属于计算智能的分支,核心不是套用经典数值解法,而是借生物进化机制去逼近可行解。当目标函数不可导、或局部极值密布导致序列法容易卡死时,这类群体算法往往更扛造。 面对高维复杂问题,群体式搜索的优势在于能较快捞到‘够用’的次优解,而不是死磕理论最优——实盘调参场景下,次优但稳健通常比理论最优更有价值。外汇与贵金属波动具有高噪声、高杠杆风险,任何优化结果都只能作为概率倾向,不能直接当确定性信号。

  • 年 Chengai 等人提出的思维进化计算(MEC)不模拟人脑,而是建模人类社会行为:每个个体是群体中的智能体,决策受本组成员与其他组影响;个体想获得更高地位就向组内最成功者学习,而团队间竞争又迫使所有人遵循同一套原则。MEC 的关键在组内与组间持续交换信息,相当于用‘信息自由流动’驱动社会式进化。

MEC 用局部竞争做局部搜索、用异化操作做全局搜索,并设留言板记录种群进化历史,据此反控优化进程。想在 MT5 里验证,可先按这个结构搭一个种群历史缓存,观察留言板信息如何改变下一代采样分布。

「把人群互动映射成多群体搜索」

MEC 本质是把人类社会里主流与异端思想的竞争搬进优化器:每个「思想」是一组参数向量,其下可长「意识形态分支」,相当于局部群体。原始 SMEC 用正态分布在组内核周围撒点做局部竞争,再用异化操作删掉垫底组、补新组控全局搜索。 实战里这套容易陷局部极值,所以把正态分布换成 Levy 飞行定律更划算——伪代码里主导组除最后一个想法外,其余分支按 Levy 律偏移,最后一个则随机抽本组某个想法的理论值拼装,组合能力明显强于纯随机初始化。 类骨架先立住:S_Idea 只存坐标与适应度,Init 用 -DBL_MAX 占位;C_AO_MEC 管两组思想数组 leadIdeolGroup / alteIdeolGroup 和全局最优 cB、fB。下面这段是结构原样,逐行看就懂数据怎么落袋。 struct S_Idea 定义想法结构;Init 方法按 size 重设坐标数组 c,并把适应度 f 置为 -DBL_MAX 表示未评估。class C_AO_MEC 公开了 cB 最佳坐标数组、fB 最佳适应度、idBr 意识形态分支数组,后续 Moving / Revision 都围着这几个成员转。 外汇与贵金属参数寻优用这类算法属高风险:回测漂亮不等于实盘能跑,Levy 步长调错可能几代就发散。

MQL5 / C++
<span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span>
<span class="keyword">class="kw">struct</span> S_Idea
{
&nbsp;&nbsp;<span class="keyword">class="type">void</span> Init(<span class="keyword">class="type">int</span> size)
&nbsp;&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;<span class="functions">ArrayResize</span> (c, size);
&nbsp;&nbsp;&nbsp;&nbsp;f = -<span class="macro">DBL_MAX</span>;
&nbsp;&nbsp;}
&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> c []; <span class="comment">class=class="str">"cmt">//coordinates</span>
&nbsp;&nbsp;<span class="keyword">class="type">class="kw">double</span> f;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//fitness</span>
};
<span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span>
<span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span>
<span class="keyword">class</span> C_AO_MEC
{
&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//----------------------------------------------------------------------------</span>
&nbsp;&nbsp;<span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> cB&nbsp;&nbsp; []; <span class="comment">class=class="str">"cmt">//best coordinates</span>
&nbsp;&nbsp;<span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> fB;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="comment">class=class="str">"cmt">//FF of the best coordinates</span>
&nbsp;&nbsp;<span class="keyword">class="kw">public</span>: S_Idea idBr []; <span class="comment">class=class="str">"cmt">//ideological branches</span>

把搜索边界和思维力灌进类里

族群优化器的公开接口先定义三组边界数组:rangeMax、rangeMin、rangeStep,分别约束每个维度的上界、下界与搜索步长。这三个数组长度必须等于坐标维数,否则后续 Init 会越界。 Init 是构造函数式入口,接收 coordinatesNumberP(坐标数)、populationSizeP(种群规模)、ideasNumberP(想法数)、thoughtPowerP(思维力,浮点)。调用时若 ideasNumberP 设 50、populationSizeP 设 100,意味着每代维护 100 个候选解、从中抽 50 个想法交互。 私有侧用三个 S_Idea 数组分装领先组、备选组、临时组,外加 vect/ind/val 辅助数组记录向量与排序索引。Sorting 负责按适应度重排想法,SeInDiSp 做带步长的离散空间映射,RNDfromCI 在闭区间取均匀随机数。 开 MT5 新建 EA 把这段类声明贴进 header,先只改 rangeMin[0]=-1.0、rangeMax[0]=1.0、rangeStep[0]=0.01 跑一维参数寻优,看 thoughtPower 在 0.3 与 0.7 下收敛代数的差异,外汇与贵金属品种波动剧烈,这类寻优结果仅代表历史样本倾向,实盘仍属高风险。

MQL5 / C++
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      ideasNumberP,          class=class="str">"cmt">//ideas number
                          const class="type">class="kw">double thoughtPowerP);          class=class="str">"cmt">//thought power
class="kw">public: class="type">void Moving();
class="kw">public: class="type">void Revision();
class=class="str">"cmt">//----------------------------------------------------------------------------
class="kw">private: S_Idea leadIdeolGroup []; class=class="str">"cmt">//leading ideological group
class="kw">private: S_Idea alteIdeolGroup []; class=class="str">"cmt">//alternative ideological group
class="kw">private: S_Idea tempIdeolGroup []; class=class="str">"cmt">//temporal ideological group
class="kw">private: class="type">int     coordinatesNumber; class=class="str">"cmt">//coordinates number
class="kw">private: class="type">int     populationSize;     class=class="str">"cmt">//population size
class="kw">private: class="type">int     ideasNumber;        class=class="str">"cmt">//ideas number
class="kw">private: class="type">class="kw">double  thoughtPower;       class=class="str">"cmt">//thought power
class="kw">private: class="type">int     ideasBr;            class=class="str">"cmt">//number of ideological branches
class="kw">private: class="type">int     leadIdGroupSize;    class=class="str">"cmt">//leading ideological group size
class="kw">private: class="type">int     alteIdGroupSize;    class=class="str">"cmt">//alternative ideological group size
class="kw">private: class="type">class="kw">double  vect      [];       class=class="str">"cmt">//vector
class="kw">private: class="type">int     ind       [];
class="kw">private: class="type">class="kw">double  val       [];
class="kw">private: class="type">bool    revision;
class="kw">private: class="type">void    Sorting(S_Idea &ideas []);
class="kw">private: class="type">class="kw">double  SeInDiSp(class="type">class="kw">double In, class="type">class="kw">double InMin, class="type">class="kw">double InMax, class="type">class="kw">double Step);
class="kw">private: class="type">class="kw">double  RNDfromCI(class="type">class="kw">double min, class="type">class="kw">double max);
};

class="type">void C_AO_MEC::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      ideasNumberP,          class=class="str">"cmt">//ideas number

常见问题

MEC用多个子群体并行搜索并周期性交换最优解,相当于让几拨人分头找路再碰头比对,比单线梯度下降更不容易困在局部洼地。
算法里‘趋同’阶段让同群个体向优者靠拢,‘异化’阶段让表现差的群被淘汰、新群随机重生,这就是模仿群体聚拢与解散的社会行为。
可以,把品种和指标范围告诉小布,它能调用内置优化流程替你跑多群体搜索,并把候选参数和回测概览整理好给你看。
会,边界越大解空间越空旷,建议先按历史波动缩到合理区间,再把‘思维力’步长设为边界的5%~10%起步。
MEC概念更贴近‘分组讨论’,没有交叉变异那堆算子要调,想快速验证策略想法可先从MEC基础版上手。