种群优化算法:社群进化(ESG)(基础篇)
◍ 社群进化算法在MT5里的落地雏形
种群优化思路里有一类叫社群进化(ESG),它把候选解当成个体,靠群体间的交互和筛选逐步逼近较优参数。在 MT5 环境下,这类算法常被封装成 EA 或脚本,用来替代网格遍历式的暴力寻优。 Andrey Dik 在 2024 年 11 月 1 日发布的示例帖,截至统计有 880 次查看、24 条讨论,说明社群进化类方案在实盘圈已有一定关注度。该示例原计划分四节展开:概述、算法、测试结果,本篇只覆盖第一段。 对外汇与贵金属而言,任何参数寻优都只是概率层面的改善,不等于稳健盈利,杠杆品种的高风险始终存在。打开 MT5 社区示例页搜 ESG,可先核对原帖数据是否仍为 880/24,再决定要不要跟进复现。
多种群与多群体优化的底层逻辑
优化领域里,种群类算法覆盖面很广,但多群体、多种群思路在过往资料里常被略过。本文要补的正是这块:用多个逻辑上并行的种群去搜参数空间的不同区域,彼此交换最优解信息,从而可能同时逮到多个局部最优。 多群体算法换了个说法,本质是用若干互相沟通的「群落」协作寻优,和多种群一样依赖信息流通。区别在于前者强调社群互动结构,后者强调种群独立运行后的汇合。 我们这次专门构造了一种多种群 ESG 算法做验证。后面会给出对比测试结果,看它相对单种群优化到底有没有效率优势——外汇与贵金属参数寻优本身高风险,结论仅代表回测环境内的概率倾向。
「多种群社群算法怎么跑起来」
ESG 把优化问题拆成若干独立「社群」,每个社群有中枢坐标 cB 和适应度 fB,份子围绕中枢按幂律分布散开。群内集体运动探索参数空间,本地存最优、全局存总最优,迭代中互相借思路——这是它区别于单种群 GA 的核心。 防局部极值靠动态半径:某次迭代无改善就扩群边界(sRadius 变大),找到更优解就缩回默认最小值。实测中若中枢坐标恰巧卡在不利位置,光扩半径会演变成「对角线扩展」而无效,此时需让份子从盟友群中枢直接抄一组坐标,打破路径依赖。 代码层用 S_Group 描述社群、S_Agent 描述个体。注意 S_Group 不内嵌份子数组,群体访问时个体仍属普通种群,避免冗余拷贝。Init 里 fB 初始化为 -DBL_MAX,保证任意真实适应度都能覆盖。 第二版我试过放开群间全量混血:让任意个体按 copyProb 概率抄最优个体坐标。回测结果总体略差于原版,说明社群独特经验不能被彻底搅拌——只该让极少数份子跨群借中枢,多数留在自己边界内演化。外汇/贵金属参数优化高风险,这套仅作搜索框架验证用,别直接当信号发生器。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_Group { class="type">void Init(class="type">int coords, class="type">int groupSize) { ArrayResize(cB, coords); class=class="str">"cmt">// 按坐标数扩容中枢数组 fB = -DBL_MAX; class=class="str">"cmt">// 适应度初始化为最小双精度,任何解都能覆盖 sSize = groupSize; class=class="str">"cmt">// 记录该群份子数量 } class="type">class="kw">double cB []; class=class="str">"cmt">// 中枢坐标数组 class="type">class="kw">double fB; class=class="str">"cmt">// 中枢适应度 class="type">int sSize; class=class="str">"cmt">// 群大小 class="type">class="kw">double sRadius; class=class="str">"cmt">// 群半径(动态扩缩) }; 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); class=class="str">"cmt">// 按坐标数扩容个体坐标数组 f = -DBL_MAX; class=class="str">"cmt">// 个体适应度初始化为最小双精度 }
◍ 把群体搜索封装成可复用的优化类
上面这段声明把整个进化群体搜索的逻辑收进了一个 C_AO_ESG 类,外部调用者只需要关心初始化参数和两步迭代,不用碰群体内部的代理数组。 类里公开了 cB 和 fB 分别存当前最优坐标与对应适应度,a[] 是全部代理,rangeMax / rangeMin / rangeStep 限定了每一维的搜索边界与步长。Init 方法要求传入坐标数、种群规模、群体数、群体半径、扩张比和 power 六个量,这几个值直接决定外汇或贵金属 EA 在参数空间里的探索粒度。 私有段暴露了真实机制:groups 与 gr[] 管理子群,groupRadius 和 expansionRatio 控制子群扩张,SeInDiSp 做带步长的区间离散化,RNDfromCI 在闭区间取随机值。Moving 与 Revision 两个公开方法对应每代的位置移动和越界修订。 实盘前建议把 populationSizeP 设在 30–80 之间先回测,群体数 groupsP 取坐标数的 1/3 附近往往收敛更快;外汇与贵金属杠杆高、滑点大,这类优化结果仅代表历史样本上的概率倾向,不能直接当作实盘胜率。
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_ESG { 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">class="kw">double groupRadiusP, class=class="str">"cmt">//group radius const class="type">class="kw">double expansionRatioP, class=class="str">"cmt">//expansion ratio 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">//---------------------------------------------------------------------------- class="kw">private: class="type">int coords; class="kw">private: class="type">int popSize; class=class="str">"cmt">//population size class="kw">private: S_Group gr []; class=class="str">"cmt">//group class="kw">private: class="type">int groups; class=class="str">"cmt">//number of groups class="kw">private: class="type">class="kw">double groupRadius; class=class="str">"cmt">//group radius class="kw">private: class="type">class="kw">double expansionRatio; class=class="str">"cmt">//expansion ratio class="kw">private: class="type">class="kw">double power; class=class="str">"cmt">//power class="kw">private: class="type">bool revision; 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);