人工蜂巢算法(ABHA):测试与结果(基础篇)
「ABHA 算法的 MT5 实测起点」
人工蜂巢算法(ABHA)在 MetaTrader 5 上的实现进入实测阶段,由测试者于 2025 年 3 月 6 日 08:55 提交首轮记录,原始线程获 784 次浏览、4 条反馈。 该轮测试并未给出收益曲线,重点在于验证算法在 MT5 策略测试器中的可运行性与稳定性,属于「继续算法实现」后的第一轮落地检验。 外汇与贵金属品种波动剧烈、杠杆风险极高,ABHA 的任何回测结果都仅代表历史样本,实盘表现可能偏离。打开 MT5 的「文件→打开数据文件夹→MQL5→Experts」即可准备放入后续 EA 文件做复验。
ABHA 智能体模型的核心约束
ABHA 把每只蜜蜂建模为独立智能体,行为由四种状态调节:新手、有经验、搜索、食物源。同一套规则集对所有蜜蜂生效,但空间位置不同导致感知环境不同,行为分支自然分化。 单只蜜蜂在任一时刻的动作,由可获得的内部与外部信息加上动机状态共同决定,符合一组固定规则。这意味着你跑回测时,不同初始坐标的 agent 即使参数一致,轨迹也会明显分叉。 蜜蜂会依据觅食经验或动机状态切换行为模式,所以模型本质是一组随个体特征与环境自适应的规则集合,而非单一全局寻优函数。外汇与贵金属市场高频跳空多,直接套该模型做价格寻优须警惕过拟合风险。
◍ ABHA 各阶段行为方法的实现逻辑
ABHA 算法把蜂群拆成新手、经验蜂、搜索蜂、食物源蜂四类,各自由 C_AO_ABHA 类里不同的 Stage 与 ChangingState 方法驱动。新手靠 StageActivityNovice 决定每一步是随机搜还是跟舞:用 u.RNDprobab() 出的随机数比 randomSearchProbability 小就调 ActionRandomSearch,否则调 ActionFollowingDance(c, val),遍历 coords 个维度逐坐标更新。 经验蜂的 StageActivityExperienced 多了一层停留逻辑:rnd ≤ agent.p_srs 随机搜,p_srs < rnd ≤ agent.p_rul 跟舞,其余情况调 ActionHiveVicinity(c, agent.bestPosition[c]) 留在已知最优位附近,策略比新手更复杂。 ActionFollowingDance 用轮盘赌选舞者——先累加所有经验蜂的 p_si 得 totalProbability,归一化随机值后命中即选该蜂,新位置 = val + (选中蜂最佳位−val) + 噪声,没选中则退回随机搜。ActionMovingDirection 让智能体按 agent.direction[coordInd] 走 agent.stepSize,走完步长乘 stepSizeReductionFactor 衰减,逼出精细收敛。 状态切换里有个硬阈值:当前 cost 比群体 avgCost 高 20% 时,经验蜂或搜索蜂直接进 stateSource 且 pab 置 1;搜索蜂若 searchCounter 触到 maxSearchAttempts 仍无突破,则降回 stateNovice 重来。外汇与贵金属参数优化属高风险实验,这套概率切换在 MT5 里跑前应先以小样本回测验证收敛倾向。 ChangingStateForSource 给食物源蜂留了退出通道:cost 低于 avgCost 时按 abandonmentRate 削 pab,一旦 u.RNDprobab() 超出现 pab 就弃源转搜索并重置方向与步长;若 cost 破 bestCost 则升经验蜂并锁 pab=1,准备向群体播报优质源。
「蜜蜂行为的概率分流与坐标更新」
ABHA 算法里,ChangingStateForSource 决定单只蜜蜂是留守食物源还是另觅出路,判断时同时比对它自己的当前值和全局最优值。真正把「去哪」落地的,是 CalculateProbabilities:先扫一遍 popSize 只蜜蜂,把 maxCost 从最小可能值往上抬、minCost 从最大可能值往下压,求出 costRange 做归一化分母。 每只蜜蜂会算出三个动作概率——p_si 随成本走高而走高,p_srs 是预设的随机搜索概率,p_rul 是跟随舞蹈概率;留守概率 p_ab 等于自身 pab。三者求和后再分别除以总和,保证概率和恒为 1,这一步直接决定下一轮是乱飞、跟舞还是趴窝。 CalculateAverageCost 顺手把全群平均成本算出来,作为群体成功度的标尺,也喂给后续决策。下面这段 C_AO_ABHA 的方法把概率变成了实际坐标动作,新手蜂只看 randomSearchProbability 二分,老手蜂则严格按 p_srs、p_rul 区间切分三种行为。 外汇与贵金属市场波动剧烈、杠杆风险高,把这类群体算法接进 MT5 做信号过滤时,回测务必覆盖滑点与点差突变,否则蜂群再聪明也扛不住实盘噪声。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//Actions class="num">1 or class="num">2 class="type">void C_AO_ABHA::StageActivityNovice(S_ABHA_Agent &agent) { class="type">class="kw">double val; for (class="type">int c = class="num">0; c < coords; c++) { val = agent.position [c]; if (u.RNDprobab() < randomSearchProbability) agent.position [c] = ActionRandomSearch(c); else agent.position [c] = ActionFollowingDance(c, val); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//actions class="num">1 or class="num">2 or class="num">4 class="type">void C_AO_ABHA::StageActivityExperienced(S_ABHA_Agent &agent) { class="type">class="kw">double rnd = class="num">0; for (class="type">int c = class="num">0; c < coords; c++) { rnd = u.RNDprobab(); class=class="str">"cmt">// random search probability if (rnd <= agent.p_srs) { agent.position [c] = ActionRandomSearch(c); } else { class=class="str">"cmt">// Probability of following the dance if (agent.p_srs < rnd && rnd <= agent.p_rul) { agent.position [c] = ActionFollowingDance(c, agent.position [c]); } class=class="str">"cmt">// Probability of remaining near the source else { agent.position [c] = ActionHiveVicinity(c, agent.bestPosition [c]); } } } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//Actions class="num">3 class="type">void C_AO_ABHA::StageActivitySearch(S_ABHA_Agent &agent) { for (class="type">int c = class="num">0; c < coords; c++) { agent.position [c] = ActionMovingDirection(agent, c); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//Actions class="num">4 class="type">void C_AO_ABHA::StageActivitySource(S_ABHA_Agent &agent) { class="type">class="kw">double val = class="num">0; for (class="type">int c = class="num">0; c < coords; c++) { agent.position [c] = ActionHiveVicinity(c, agent.bestPosition [c]); } } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//class="num">1. Random search(random placement in a range of coordinates) class="type">class="kw">double C_AO_ABHA::ActionRandomSearch(class="type">int coordInd) { class="kw">return u.RNDfromCI(rangeMin [coordInd], rangeMax [coordInd]); } class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//class="num">2. Follow the dance(move in the direction of the dancer) class="type">class="kw">double C_AO_ABHA::ActionFollowingDance(class="type">int coordInd, class="type">class="kw">double val) {