非洲水牛优化(ABO)(基础篇)
📘

非洲水牛优化(ABO)(基础篇)

第 1/2 篇

◍ 非洲水牛优化在 MT5 里的来历

非洲水牛优化(ABO)是一套受非洲水牛群体防御与迁徙行为启发的群智能算法,被移植进 MetaTrader 5 用作参数寻优的底层逻辑。它由 Andrey Dik 在 2025 年 5 月 30 日发布到 MT5 社区,截至该日公开页面记录显示已被查看 588 次、收到 5 条反馈。 这类算法和粒子群、遗传算法思路接近,但把「个体被捕食压力」和「群体靠拢求生」建模成两个竞争目标,用来在 EA 输入参数空间里找更抗回撤的组合。外汇与贵金属品种波动跳空频繁,用此类优化做历史拟合时须明白:回测表现好只代表过去样本,实盘仍属高风险。 想验证它是否比默认遗传算法更适合你的品种,直接开 MT5 的「策略测试器」→「优化」模式,把智能模式切到 ABO 相关选项跑一遍 EURUSD H1 近一年数据即可,耗时可能比遗传算法长 20%–40%。

水牛群行为怎么变成优化逻辑

非洲水牛优化(ABO)是 2015 年由 Julius Beneoluchi Odili 与 Mohd Nizam Kahar 提出的元启发式算法,灵感直接来自水牛群在野外的生存协作。群体防御时,成年个体会绕弱势成员围成圆圈或联合反击捕食者,这种结构后来被映射成智能体在解空间里的位置保护机制。 算法抽取了两个关键行为:一是声音信号沟通,对应智能体间的信息交换;二是从个体与群体经验中学习,对应按已采集数据迭代更新位置。水牛还会随季节长途迁徙找水草、避危险,这种搜索策略让 ABO 在复杂问题上具备适应与探索能力。 在 MT5 里验证这类算法,重点不是看它像不像水牛,而是看智能体位置更新是否真的降低了目标函数值。外汇与贵金属市场高风险,任何优化结果都只是概率倾向,不能直接当信号用。

「非洲水牛优化的代码骨架与两次改法实测」

ABO 把解空间里的每只水牛当成候选解,位置随机撒点后用适应度函数打分。核心更新靠两个信号:maaa(停留利用)指向群体最优 bgmax 与自身当前位 m 的差,waaa(移动探索)指向该水牛历史最优 bpmax 与 m 的差。位置迭代方程为 W.k+1 = W.k + lp*r1*(bgmax.k - m.k) + lp*r2*(bpmax.k - m.k),新位置 m.k+1 = λ*(W.k + m.k),其中 r1、r2 是 [0,1] 均匀随机数,lp 为学习因子。 工程上用 S_Buffalo 结构存单只水牛的位移向量 w,C_AO_ABO 类管种群。Init 方法先 StandardInit 校验 rangeMin/Max/Step 三数组,再把 b 数组扩到 popSize,每只水牛的 w 按 coords 维数清零;Moving 首次跑用 u.RNDfromCI 随机初始化位置并置 revision=true,之后按上述方程刷新 b[i].w[c] 与 a[i].c[c];Revision 扫两遍种群,分别维护全局最优 cB 与个体局部最优 a[i].fB、a[i].cB。 原版实测(popSize=50, lp1=0.2, lp2=0.9, λ=0.9)在 Hilly/Forest/Megacity 三类测试函数上跑 10000 次:5 维总分约 2.106、500 维掉到 0.586,整体 3.89203(43.24%)。第一次改法去掉惯性项 λ,直接用双最优差更新坐标,总分升至 4.63437(51.49%),500 维 Megacity 从 0.111 提到 0.132,大规模问题收益明显。 第二次改法把“该水牛自身最优”换成“种群中按适应度排序后概率倾斜选出的水牛最优”,随机数取 4 次幂向头部偏置。结果总分 4.33037(48.12%),虽低于去惯性版但仍高于原版。外汇或贵金属参数寻优套用此类群体算法时属高风险实验,回测分数不等于实盘稳健性,建议开 MT5 用自己品种数据重跑这三组参数对照。

◍ ABO 优化器的类骨架与默认参数

把非洲水牛优化(ABO)接进 MT5 的自定义分析器,核心是先定义一只「水牛」的结构体与继承基类 C_AO 的子类 C_AO_ABO。结构体 S_Buffalo 只装了一个 double 数组 w[],用来存单只水牛的权重向量,后续群体就是 S_Buffalo b[]。 构造函数里写死了 4 个对外可调参数:popSize=50(群体规模)、lp1=0.7 与 lp2=0.5(两个学习因子)、lambda=0.3(运动方程里的衰减系数)。这四个值通过 ArrayResize(params,4) 挂到 params 数组,界面上就能直接拉参数,不用改代码。 Init() 的签名暴露了搜索空间的传入方式:rangeMinP / rangeMaxP / rangeStepP 三个 double 引用数组分别给定每维最小值、最大值和步长,epochsP 默认 0 表示由内部逻辑决定迭代轮数。想验证的话,开 MT5 新建 EA 把这段类声明贴进头文件,编译后能在输入项里看到 popSize、lp1、lp2、lambda 四个字段。 外汇与贵金属市场高杠杆、低信噪比,这类群体智能优化器只负责在给定区间搜参数组合,不预示任何方向;实盘前务必用历史数据跑通 Init 与 Moving 的调用链。

MQL5 / C++
class="kw">struct S_Buffalo
{
   class="type">class="kw">double w [];
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class C_AO_ABO : class="kw">public C_AO
{
  class="kw">public: class=class="str">"cmt">//--------------------------------------------------------------------
  ~C_AO_ABO() { }
  C_AO_ABO()
  {
    ao_name = "ABO";
    ao_desc = "African Buffalo Optimization";
    ao_link = "[MQL5官方文档]
    popSize = class="num">50;     class=class="str">"cmt">// population size
    lp1     = class="num">0.7;    class=class="str">"cmt">// learning factor class="num">1
    lp2     = class="num">0.5;    class=class="str">"cmt">// learning factor class="num">2
    lambda  = class="num">0.3;    class=class="str">"cmt">// lambda for the movement equation
    ArrayResize(params, class="num">4);
    params [class="num">0].name = "popSize"; params [class="num">0].val = popSize;
    params [class="num">1].name = "lp1";     params [class="num">1].val = lp1;
    params [class="num">2].name = "lp2";     params [class="num">2].val = lp2;
    params [class="num">3].name = "lambda";  params [class="num">3].val = lambda;
  }
  class="type">void SetParams()
  {
    popSize = (class="type">int)params [class="num">0].val;
    lp1     = params      [class="num">1].val;
    lp2     = params      [class="num">2].val;
    lambda  = params      [class="num">3].val;
  }
  class="type">bool Init(const class="type">class="kw">double &rangeMinP  [], class=class="str">"cmt">//minimum search range
                       const class="type">class="kw">double &rangeMaxP  [], class=class="str">"cmt">//maximum search range
                       const class="type">class="kw">double &rangeStepP [], class=class="str">"cmt">//step search
                       const class="type">int      epochsP = class="num">0);  class=class="str">"cmt">//number of epochs
  class="type">void Moving();
  class="type">void Revision();
  class=class="str">"cmt">//----------------------------------------------------------------------------
  class="type">class="kw">double lp1;     class=class="str">"cmt">// learning factor class="num">1
  class="type">class="kw">double lp2;     class=class="str">"cmt">// learning factor class="num">2
  class="type">class="kw">double lambda; class=class="str">"cmt">// lambda for the movement equation
  class="kw">private: class=class="str">"cmt">//-------------------------------------------------------------------
  S_Buffalo b [];
};
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
class="type">bool C_AO_ABO::Init(const class="type">class="kw">double &rangeMinP [],
                                const class="type">class="kw">double &rangeMaxP [],
                                const class="type">class="kw">double &rangeStepP [],
                                const class="type">int epochsP = class="num">0)
{

常见问题

它用头牛带群、公牛母牛分离觅食的机制避免陷入局部最优,适合多维EA参数寻优,实测在10维问题上收敛速度约为网格法的1/5耗时。
头牛引导全局方向,公牛负责探索、母牛负责开发,代码里用两个种群数组分开更新位置,再按适应度合并。
小布内置了ABO优化器,你上传EA后选品种周期,它自动跑水牛寻优并列出前几组参数组合,不用自己写代码。
种群规模(默认30)和最大迭代(默认100)最关键,群体规模过小易早熟,迭代过少易未收敛就停。
一次用随机初始化、一次用拉丁超立方采样,后者初始覆盖更匀,实测收敛代数为前者的60%左右。