种群优化算法:Boids(虚拟生物)算法(基础篇)
用鸟群模型给价格找共振区
Boids 算法原本是模拟鸟群飞行的多智能体模型,核心只有三条局部规则:分离、对齐、聚合。把它移植到 MT5 上,可以用一群虚拟生物在价格空间里游走来标记多空力量的聚集带。 在 MQL5 里跑这套逻辑,本质是把每个 Boids 个体当作一个价格观察者,按 tick 更新位置。当大量个体在某价位区间反复聚合,该区域形成概率较高的支撑或阻力带,可用于人工复核入场。 外汇与贵金属属高杠杆高风险品种,这类聚集带仅作参考,不预示必反转;实际用 EA 验证时建议先开策略测试器用 2023 年 EURUSD 的 H1 数据回测,观察聚合带与影线触碰的频率再决定是否上实盘。
◍ 从鸟群本能到Boids三条铁律
看自然界兽群迁徙,最扎眼的是它们没中央指挥却能同步避障、找最优路径。这种靠简单局部交互涌现整体秩序的现象,直接催生了一批元启发优化算法。 1986年Craig Reynolds把“bird”和“-oid”拼成Boids,用三条规则模拟鸟群:分离(避撞)、对齐(跟邻居平均方向)、凝聚(靠向邻居平均位置)。仅这三条,就能在计算机里复现昆虫群、鱼群的复杂运动。 原版Boids本是为动画逼真度而生,后来溢出了行为模式研究、机器人编队、交通流管理。它也哺育了PSO粒子群这类后续算法,至今仍是集体行为建模的热门基底。 在MT5里按F3会弹出Boids设置窗;把“#reset”置1可重启算法。实时改参数能直接看到群体从松散到紧凑的变化,外汇贵金属行情虽无鸟群,但这类集群逻辑对识别散户跟风盘有高风险参考意义。
「把鸟群行为搬进优化搜索」
Craig Reynolds 的 Boids 模型原本是模拟鸟群、虫群用的,但它那套去中心化规则后来被挪到优化和搜索里。和传统梯度下降或遗传算法不同,Boids 本身不保证在解空间里找全局最优,而是让一组 agent 按简单规则互动,在群体层面冒出复杂协调行为。把它当函数极值分布式搜索器用时,每个 boid 就是空间里一个会动的搜索点,既能看自己位置的函数值,也能参考邻居的适应度。 这套算法外参很多,且直接改写群体运动特征:cohesionWeight / cohesionDist 管相互吸引的强度和触发距离,separationWeight / separationDist 管排斥避免重叠,alignmentWeight / alignmentDist 管运动方向趋同,minSpeed / maxSpeed 卡住速度上下限。实验上不存在绝对“正确”的参数,只能从建议值起手逐步调,看群体是抱团还是散开。 代码里先定义 S_Boids_Agent 结构描述单个智能体,x[] 存坐标、dx[] 存速度、m 是作者主动加的字段,用来把适应度曲面上的集群质量纳入移动考量。C_AO_Boids 类继承自种群算法基类,公开字段涵盖上述全部权重距离与 popSize,私有里算好了 distanceMax 和 speedMax 供移动阶段使用。 Moving 方法每轮先读全局 reset 与参数,revision 为 false 时随机撒坐标和速度;否则对每个 agent 依次跑 CalculateMass、Cohesion、Separation、Alignment、LimitSpeed、KeepWithinBounds 更新速度再推坐标。CalculateMass 按适应度最大最小值给每个 boid 算 m,补上了原算法缺的“地形”感知;Revision 则扫一遍种群,把更优的 a[i].f 写进 fB 和 cB,让搜索偏向有前景区域。外汇与贵金属参数优化属高风险,回测参数迁移到实盘可能失效。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_Boids_Agent { class="type">class="kw">double x []; class="type">class="kw">double dx []; class="type">class="kw">double m; class="type">void Init(class="type">int coords) {
把 Boids 群智参数接进指标类
上面这段是 C_AO_Boids 类的构造与参数接管逻辑,它把群智能算法(Boids)直接挂到自定义指标框架里。构造函数里先写死一组默认参数:种群规模 50,聚合权重 0.6、聚合距离 0.001,分离权重 0.005、分离距离 0.03,对齐权重 0.1、对齐距离 0.1,最大速度 0.001、最小速度 0.0001。 这组数字不是随便填的。cohesionDist 用 0.001 这种极小量,说明算法跑在归一化价格空间(比如 0~1 区间),而不是裸点位;separationDist 给到 0.03 比 cohesionDist 大 30 倍,意味着个体间「怕挤」的阈值远高于「向中心靠」的触发范围,群态会更松散。 params 数组长度设成 9,和上面 9 个变量一一对应,name 存字符串、val 存默认值。SetParams() 不做计算,只把 params 里的值回写进类成员变量,相当于给外部面板留了实时调参通道——你在 MT5 里拖一下滑动条,下一帧 Boids 的游动规则就变。 外汇和贵金属波动剧烈,这类算法指标仅作形态参考,实盘信号概率性成立,高杠杆下随时可能反向扫损。
class C_AO_Boids : class="kw">public C_AO { class="kw">public: class=class="str">"cmt">//-------------------------------------------------------------------- ~C_AO_Boids() { } C_AO_Boids() { ao_name = "Boids"; ao_desc = "Boids Algorithm"; ao_link = "[MQL5官方文档] popSize = class="num">50; class=class="str">"cmt">//population size cohesionWeight = class="num">0.6; cohesionDist = class="num">0.001; separationWeight = class="num">0.005; separationDist = class="num">0.03; alignmentWeight = class="num">0.1; alignmentDist = class="num">0.1; maxSpeed = class="num">0.001; minSpeed = class="num">0.0001; ArrayResize(params, class="num">9); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "cohesionWeight"; params [class="num">1].val = cohesionWeight; params [class="num">2].name = "cohesionDist"; params [class="num">2].val = cohesionDist; params [class="num">3].name = "separationWeight"; params [class="num">3].val = separationWeight; params [class="num">4].name = "separationDist"; params [class="num">4].val = separationDist; params [class="num">5].name = "alignmentWeight"; params [class="num">5].val = alignmentWeight; params [class="num">6].name = "alignmentDist"; params [class="num">6].val = alignmentDist; params [class="num">7].name = "maxSpeed"; params [class="num">7].val = maxSpeed; params [class="num">8].name = "minSpeed"; params [class="num">8].val = minSpeed; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; cohesionWeight = params [class="num">1].val; cohesionDist = params [class="num">2].val; separationWeight = params [class="num">3].val; separationDist = params [class="num">4].val; alignmentWeight = params [class="num">5].val; alignmentDist = params [class="num">6].val; maxSpeed = params [class="num">7].val; minSpeed = params [class="num">8].val; } class="type">bool Init(class="kw">const class="type">class="kw">double &rangeMinP [], class=class="str">"cmt">//minimum search range