种群优化算法:细菌觅食优化(BFO)(基础篇)
「用细菌觅食思路给 EA 找参数」
细菌觅食优化(BFO)把参数搜索模拟成菌群找食物:每只「细菌」代表一组 EA 参数,朝历史回测中更优的收益方向游动,并靠复制、迁徙避免陷在局部极值。这套思路在 MT5 里可以直接接进策略测试器的优化框架。 原文给出的示例发布于 2023 年 6 月 1 日,至统计时已有 1467 次查看、8 条讨论,说明社群里确实有人在拿它跑实盘前验证。外汇与贵金属杠杆高,回测优不代表实盘稳,任何参数组合都先用 MT5 策略测试器做样本外检验再上。 想动手的话,先把 EA 的输入参数暴露成可优化变量,再写一层 BFO 循环去调度它们;下一段给一个最朴素的菌群初始化片段。
◍ 把大肠杆菌的游泳翻滚搬进优化器
细菌觅食优化(BFO)的核心,是用大肠杆菌的社会觅食行为去逼近复杂函数的极值。它不属于梯度法,而是在高维、多峰、甚至不可导的空间里靠群体随机探索找近似解,外汇与贵金属参数寻优这类非凸问题里可能比网格暴力搜更高效,但同样伴随过拟合高风险。 大肠杆菌靠鞭毛推进:所有鞭毛逆时针转,细菌沿直线「游泳」;顺时针且方向不一致时则「翻滚」改变运动向量。原文给出的速度是每秒 10–20 倍体长,这种尺度下布朗运动干扰极强,细菌只能「平均」朝营养物质(引诱剂)移动、远离害物质(驱虫剂)。 趋化性就是细菌对化学梯度的运动反应。因为体型太小无法同时比对两极浓度,它靠运动中的浓度变化率判断梯度——浓度上升就延长本次游泳,下降就提前翻滚。BFO 里这一步等价于「沿当前方向走一步看收益,变差就随机换方向」。 Passino 把真实种群的「繁衍 / 消除 / 扩散」也写进算法:局部极值困住趋化时就靠群体迁移跳出。适应性差的个体消亡、好的自我复制,本质是自然选择。开 MT5 跑 EA 参数优化时,若只用单一种群局部搜索容易卡在次优,参考 BFO 的消除扩散机制可能提升全局覆盖概率。
BFO菌群寻优的落地逻辑与代码骨架
细菌觅食优化(BFO)规范版分五步:初始化菌群、趋化、聚集、繁衍、消除扩散。趋化靠“游动+翻滚”判定方向,聚集在成本函数里加惩罚项把菌往食物密处拉,繁衍保留健康一半替换差的一半,消除扩散则用来打破局部停滞。 实盘优化器里我用的实现跟规范版有细微差别:不标记“修改版”,但改动确实让结果更好。流程变成——初始化菌落、测适应度、判断是否繁衍(是则分裂,否则看老化)、老化到生命极限就翻滚改方向、方向对就续游不对也翻滚、再测适应度,循环到停止条件。 关键差异在生命计数器:规范版菌老死后在随机位重生,实际只会拖慢搜索;这里改成到寿命就改矢量继续游,或直接在最优解附近重生。规范版用常量运动矢量,菌会沿直线跑到天荒地老,计数器强制翻滚避免了这点。 比较健康值时我用“大于或等于”替代严格的“大于”,让菌在适应度函数全平的区域也能继续挪,否则会在原地无限翻滚。繁衍按健康降序排,前半健康菌分裂,克隆体拿新矢量从分裂点出发,菌总数恒定。 下面这段结构体和类声明是整套逻辑的容器,坐标、运动矢量、当前/前次健康、生命计数都在 S_Bacteria 里;C_AO_BFO 管菌落数组、边界、最优解和参数。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_Bacteria { class="type">class="kw">double c []; class=class="str">"cmt">//coordinates class="type">class="kw">double v []; class=class="str">"cmt">//vector class="type">class="kw">double f; class=class="str">"cmt">//current health class="type">class="kw">double fLast; class=class="str">"cmt">//previous health class="type">class="kw">double lifeCNT; class=class="str">"cmt">//life counter }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class C_AO_BFO { class=class="str">"cmt">//---------------------------------------------------------------------------- class="kw">public: S_Bacteria b []; class=class="str">"cmt">//bacteria 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">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: class="type">void Init(class="kw">const class="type">int paramsP, class=class="str">"cmt">//number of opt. parameters class="kw">const class="type">int populationSizeP, class=class="str">"cmt">//population size class="kw">const class="type">class="kw">double lambdaP, class=class="str">"cmt">//lambda
「细菌觅食优化器的类骨架与初始化」
这段 C_AO_BFO 类的声明把细菌觅食算法(BFO)的核心状态都压在了私有成员里:bT 数组存菌群,v、ind、val 分别管游动步长、索引和适应度,populationSize 与 parameters 锁定种群规模和待优化参数个数。lambda 控制趋化步长收缩,reproduction 是繁殖概率,lifeCounter 决定单菌最大存活代数,这几个量直接决定 EA 在 MT5 里的搜索粒度。 Init 函数是实盘前必须跑的通路。它先把 fB 置为 -DBL_MAX 表示尚未找到最优,evaluation 置 false;随后把传入的 paramsP、populationSizeP、lambdaP、reproductionP、lifeCounterP 逐一赋给成员。紧接着用 ArrayResize 把 rangeMax、rangeMin、rangeStep 扩到 parameters 长度,把 v 也扩到同长,ind、val、b 扩到 populationSize——若这里数组维度配错,后面 Swimming 和 Evaluation 会直接越界报错。 开 MT5 验证时,建议先打印 populationSize 与 parameters 的 Actual 值:例如设 parameters=5、populationSize=30,则 b 数组应精确扩到 30 个元素,val 长度同为 30,少一个都会在回测起始帧抛 4002 数组越界。外汇与贵金属品种波动跳变快,这类优化器参数若乱配,过拟合概率会明显抬升,属高风险操作。
class="kw">const class="type">class="kw">double reproductionP, class=class="str">"cmt">//probability of reproduction class="kw">const class="type">int lifeCounterP); class=class="str">"cmt">//life counter class="kw">public: class="type">void Swimming(); class="kw">public: class="type">void Evaluation(); class=class="str">"cmt">//---------------------------------------------------------------------------- class="kw">private: class="type">class="kw">double NewVector(class="type">int paramInd); class="kw">private: S_Bacteria bT []; class=class="str">"cmt">//bacteria class="kw">private: class="type">class="kw">double v []; class="kw">private: class="type">int ind []; class="kw">private: class="type">class="kw">double val []; class="kw">private: class="type">int populationSize; class=class="str">"cmt">//population size class="kw">private: class="type">int parameters; class=class="str">"cmt">//number of optimized parameters class="kw">private: class="type">class="kw">double lambda; class=class="str">"cmt">//lambda class="kw">private: class="type">class="kw">double reproduction; class=class="str">"cmt">//probability of reproduction class="kw">private: class="type">int lifeCounter; class=class="str">"cmt">//life counter class="kw">private: class="type">bool evaluation; class="kw">private: class="type">void Sorting(); 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=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_BFO::Init(class="kw">const class="type">int paramsP, class=class="str">"cmt">//number of opt. parameters class="kw">const class="type">int populationSizeP, class=class="str">"cmt">//population size class="kw">const class="type">class="kw">double lambdaP, class=class="str">"cmt">//lambda class="kw">const class="type">class="kw">double reproductionP, class=class="str">"cmt">//probability of reproduction class="kw">const class="type">int lifeCounterP) class=class="str">"cmt">//life counter { fB = -DBL_MAX; evaluation = false; parameters = paramsP; populationSize = populationSizeP; lambda = lambdaP; reproduction = reproductionP; lifeCounter = lifeCounterP; ArrayResize(rangeMax, parameters); ArrayResize(rangeMin, parameters); ArrayResize(rangeStep, parameters); ArrayResize(v, parameters); ArrayResize(ind, populationSize); ArrayResize(val, populationSize); ArrayResize(b, populationSize);