人工喷淋算法(ASHA)(基础篇)
◍ ASHA 喷淋算法在 MT5 的落地与测试
人工喷淋算法(ASHA)是一套跑在 MetaTrader 5 上的自动化逻辑,由 Andrey Dik 在 2025 年 7 月 21 日 07:59 发布至社区,截至统计时点获得 777 次查看、0 条评论,说明该策略当前曝光有限、讨论度极低。 算法核心分两层:概述层定义喷淋式挂单与动态间距,实现层负责在 MT5 中按波动率调整下单密度。外汇与贵金属品种波动大,ASHA 这类密集挂单逻辑在极端行情中可能放大滑点与穿仓风险,实盘前务必用策略测试器跑历史数据。 已公开的测试结果显示,该算法在标准账户样本中存在成交集中、回撤陡增的现象,但原文未给具体收益率或最大回撤数值,因此任何盈利预期都只是概率层面的推测。
「元启发式为什么适合盯盘优化」
数据量膨胀让传统数值方法在 MT5 策略调参里越来越吃力。元启发式算法靠高收敛速度和并行处理,把从金融行情拟合到科研寻优的耗时压下来,这是它打开局面的根本原因。 在严格时间窗里,每一根 tick 都可能改变信号,元启发式能在有限步内吐出比穷举更好的解。对比传统方法,它处理大样本快,且解质量往往更高,这对日内高频过滤噪音有直接价值。 算力和内存受限时(比如云 VPS 跑多品种),这类算法更省资源。对动态报价系统的适应性,让模型在新数据进来时快速重算,保持信号不过期。
- 年 Ali J. 等人提出的 ASHA(人工淋浴算法)就是典型一例:它把搜索空间当田野、资源单位当水,用流动与积聚模拟寻优,属于受自然启发的无约束优化思路,后面可直接在 MT5 里做基准对照。
人工淋浴算法在 MT5 里的代理结构与移动逻辑
ASHA(人工淋浴算法)把优化问题当成一块有坡度的田:每个水单元是一个搜索代理,目标函数越低代表地势越低。它靠几个参数控场——F 是水流量(步长),δ 是渗透阈值,β 是概率变化率,ρ₀ 是初始下坡概率。核心矛盾是 ρ 随迭代从 max((M-K)/(β×M), ρ₀) 衰减:前期乱流探底,后期被全局最低点吸住。 标准 S_AO_Agent 结构被扩了字段:c[] 当前坐标、cP[] 上次坐标、cB[] 历史最佳坐标,f/fP/fB 分别对应这三者的适应度,cnt 记代理「卡住」次数。Init() 按坐标数分配这三组数组,并把 f 系值先置到最小可能,保证首次评估必更新。这个结构改动不破坏旧算法,只是给新算法铺路。 C_AO_ASHA 类从 C_AO 继承,私有里塞了 aT[] 临时种群、epochs 总代数、epochNow 当前代。Init() 先调 StandardInit 做参数体检,再把 epochs 设为传入值、epochNow 归零、给 aT 留内存,全过才返 true。 Moving() 是重头戏:首轮用 u.RNDfromCI 撒初始点并离散化;之后每代 epochNow 自增,inf 由 u.Scale 算 cnt 的四次方影响力。对每个代理 i 和坐标 c,先随机选低位代理 ind;若 rnd<inf 就按高斯分布绕 cB 抖;否则按 ρ 决定是贴 xLower 还是贴全局 xLowest 更新,最后 u.SeInDiSp 把坐标夹回范围与步长。 渗透机制原文用固定 δ 判断 f(x_i)<δ 就随机重生,但作者指出 δ 难预设:太小不渗、太大狂重启。他的改法是给每滴加尝试计数器,泄漏概率按二次律加速,避免一滴死赖一处。Revision() 则扫全群,f 超 fB 就刷 cB、cnt 归零,否则 cnt++;找到全局最优 ind 后抄进 cB 全局并调 u.Sorting_fB 排序。外汇/贵金属参数优化属高风险,回测过拟合可能让实盘失效,建议开 MT5 用自有品种跑一遍 Moving 的 ρ 衰减节奏。
◍ ASHA 智能体的结构体与类初始化
人工淋浴算法(ASHA)把每个搜索个体封装成 S_AO_Agent 结构体,除了当前坐标 c 与适应度 f,还显式保留了上一代坐标 cP、历史最优坐标 cB 以及对应的 fP、fB,并带一个 cnt 计数器。Init 里把三类坐标数组按维度 resize,适应度统一置为 -DBL_MAX,意味着初始个体尚未评估过有效解。 继承类 C_AO_ASHA 在构造时写死了五组参数:种群规模 popSize=100、水流速度 F=0.3、渗透阈值 δ=2、概率变化率 β=0.8、初始概率 ρ0=0.1。这些量直接进 params 数组,方便在 MT5 输入面板里改值后由 SetParams 回写。 外汇与贵金属行情噪声大,用 100 个体跑进化搜索只能说提高命中概率,不代表稳定出信号;建议先把 popSize 调到 30 看回测耗时,再逐步加压。
class="kw">struct S_AO_Agent { class="type">class="kw">double c []; class=class="str">"cmt">//coordinates class="type">class="kw">double cP []; class=class="str">"cmt">//previous coordinates class="type">class="kw">double cB []; class=class="str">"cmt">//best coordinates class="type">class="kw">double f; class=class="str">"cmt">//fitness class="type">class="kw">double fP; class=class="str">"cmt">//previous fitness class="type">class="kw">double fB; class=class="str">"cmt">//best fitness class="type">int cnt; class=class="str">"cmt">//counter class="type">void Init(class="type">int coords) { ArrayResize(c, coords); ArrayResize(cP, coords); ArrayResize(cB, coords); f = -DBL_MAX; fP = -DBL_MAX; fB = -DBL_MAX; cnt = class="num">0; } }; class C_AO_ASHA : class="kw">public C_AO { class="kw">public: class=class="str">"cmt">//-------------------------------------------------------------------- ~C_AO_ASHA() { } C_AO_ASHA() { ao_name = "ASHA"; ao_desc = "Artificial Showering Algorithm"; ao_link = "[MQL5官方文档] popSize = class="num">100; class=class="str">"cmt">//population size F = class="num">0.3; class=class="str">"cmt">//water flow velocity δ = class="num">2; class=class="str">"cmt">//resistance level(infiltration threshold) β = class="num">0.8; class=class="str">"cmt">//parameter that controls the rate of change in probability ρ0 = class="num">0.1; class=class="str">"cmt">//initial probability ArrayResize(params, class="num">5); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "F"; params [class="num">1].val = F; params [class="num">2].name = "δ"; params [class="num">2].val = δ; params [class="num">3].name = "β"; params [class="num">3].val = β; params [class="num">4].name = "ρ0"; params [class="num">4].val = ρ0; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; F = params [class="num">1].val; δ = (class="type">int)params [class="num">2].val; β = params [class="num">3].val;