人工协作搜索算法 (ACS)(基础篇)
「ACS 在 MT5 里的落地起点」
人工协作搜索算法(ACS)在 MetaTrader 5 里并非黑盒,它把群体搜索和人工干预结合起来,让优化过程不完全交给EA自动跑。 作者 Andrey Dik 在 2024 年 12 月 3 日 08:59 发布的示例帖,至今累计 563 次查看、0 条评论,说明这套思路还停留在小圈子验证阶段。 该系列原文结构拆成四块:概述、算法实现、测试结果,本篇只讲第一块,后面三块由其他小节覆盖。 想确认 ACS 是否适合你的贵金属策略,先在 MT5 策略测试器里开一个简单 EA,把参数空间留白,观察优化 pass 的分布再决定要不要介入人工协作。外汇与贵金属杠杆高,任何算法都只是概率工具,不代表稳定盈利。
◍ 从共生迁徙到人工超生物体
自然界里互利共生和真社会性超生物体的集体迁徙,是很多现代优化算法的灵感底稿。开花植物靠传粉者繁殖、菌根帮植物吸水吸矿、白蚁肠道细菌消化纤维素——这些关系都指向一个事实:共享环境的个体通过协作提升整体生存概率。蚂蚁搬家带幼虫蛹、蜂群分巢带蜂王和蜜,同样是在环境变动时靠集体迁移保住种群。 ACS(Artificial Cooperative Search)算法由 Pinar Civicioglu 在 2013 年提出,直接借用了上面两类生物特性。它把优化问题的搜索空间当成栖息地,把随机解看成正在找更肥觅食区的人工超生物体。算法跑两个等规模种群 α 和 β,分别代表捕食者和猎物,子超生物体个数就是种群规模。 具体落地时,ACS 先用两个基种群在置信区域里撒候选解,再通过随机步和二进制矩阵从 α、β 映射出捕食者、猎物种群,并算出第五个衍生种群。指定迭代次数内反复更新初值、挑最优,这种双种群生物激励式互动,是它在数值优化里收敛快、精度高的主因。外汇与贵金属参数寻优属高风险场景,ACS 给出的只是概率倾向更优解,不是稳赢方案,开 MT5 用 MQL5 接自己的目标函数跑一遍才知适配度。
ACS 算法的 MT5 类结构与阶段拆分
人工写作搜索算法(ACS)在 MT5 里不是一段扁平脚本,而是从 C_AO 基类派生的 C_AO_ACS 类。种群用 S_D 结构装实数坐标数组 c[],Init 方法靠 ArrayResize 按变量数扩容;M 矩阵则用独立的 S_C 结构,同样持有 c[] 但只存 0/1 符号。类内私有成员包含 A[]、B[]、Predator[]、Prey[]、M[] 以及 YA[]、YB[]、Ypred[] 等双精度适应度数组,bioProbab 存生物交互概率。 原始 ACS 伪代码是单循环顺推,但作者在 MT5 实现里强行切了 phase 阶段——phase=0 复制 A 种群,phase=1 回算 A 适应度并复制 B,phase=2 回算 B 适应度后再跑选择、洗牌、变异、交叉。这么拆是因为 A、B 两个种群都依赖预计算适应度,而作者其他种群算法都走分阶段调用风格,不拆就串不起 Moving 与 Revision 的时序。 Moving 方法管个体位移:按随机数把 A 或 B 塞进 Predator,Prey 做 ArrayShuffle 乱序;R 因子取 4*Rand*(1-Rand) 或 1/exp(4*Rand);M 矩阵先全填 1,再以 bioProbab 概率把部分元素翻 0/1,若整行全 1 则随机清掉一个。变异用 X = Predator + R*(Prey-Predator),越界就随机重投。Revision 在 phase<3 时直接 return,之后排序 Ypred 并反转取最大值,若优于全局 fB 就更新最优向量。 洗牌逻辑本身很轻量:从尾到头遍历,j = MathRand()%(i+1) 取随机下标,交换 arr[i] 与 arr[j]。外汇/贵金属参数优化属高风险实验,ACS 只是搜索器,实盘前务必在 MT5 策略测试器用历史数据回测验证收敛性。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_D { class="type">void Init(class="type">int coords) { ArrayResize(c, coords); } class="type">class="kw">double c []; }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_C { class="type">void Init(class="type">int coords) { ArrayResize(c, coords); }
「ACS 优化器的类骨架与初始化入口」
把人工协同搜索(Artificial Cooperative Search)接进 MT5 的优化框架,核心是先派生一个 C_AO_ACS 类,它继承自通用优化器基类 C_AO,构造函数里把算法名定为 "ACS",并登记了两个可调参数:种群规模 popSize 默认 1,生物交互概率 bioProbab 默认 0.9。 这两个参数通过 ArrayResize(params, 2) 扩容参数数组后写入,名字与初值一一对应,意味着在 EA 的输入面板里能直接看到 popSize 和 bioProbab 两项。若把 bioProbab 从 0.9 往下调,个体间模仿捕食者/猎物的随机性会下降,搜索轨迹可能更集中。 类内部用 S_D 类型数组 A、B、Predator、Prey 以及 S_C 数组 M 来承载个体状态,YA、YB、Ypred 记录对应适应度,Key 和 phase 控制搜索阶段切换,私有的 ArrayShuffle 负责打乱数组顺序。 Init 函数接收搜索上下界与步长数组,可选 epochsP 默认 0,实现里先调用 StandardInit 做边界与步长合法性校验,失败直接返回 false,这是外接自定义优化器时最容易漏掉的第一道关卡。
class="type">char c []; }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class C_AO_ACS : class="kw">public C_AO { class="kw">public: class=class="str">"cmt">//-------------------------------------------------------------------- ~C_AO_ACS() { } C_AO_ACS() { ao_name = "ACS"; ao_desc = "Artificial Cooperative Search"; ao_link = "[MQL5官方文档] popSize = class="num">1; class=class="str">"cmt">//population size bioProbab = class="num">0.9; class=class="str">"cmt">//biological interaction probability ArrayResize(params, class="num">2); params [class="num">0].name = "popSize"; params [class="num">0].val = popSize; params [class="num">1].name = "bioProbab"; params [class="num">1].val = bioProbab; } class="type">void SetParams() { popSize = (class="type">int)params [class="num">0].val; bioProbab = params [class="num">1].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 bioProbab; class=class="str">"cmt">//biological interaction probability class="kw">private: class=class="str">"cmt">//------------------------------------------------------------------- S_D A []; S_D B []; S_D Predator []; S_D Prey []; S_C M []; class="type">class="kw">double YA []; class="type">class="kw">double YB []; class="type">class="kw">double Ypred []; class="type">int Key; class="type">int phase; class="type">void ArrayShuffle(class="type">class="kw">double &arr []); }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">bool C_AO_ACS::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 { if (!StandardInit(rangeMinP, rangeMaxP, rangeStepP)) class="kw">return false;