种群优化算法:微人工免疫系统(Micro-AIS)(基础篇)
◍ 把微人工免疫系统塞进 MT5 回测
微人工免疫系统(Micro-AIS)属于种群优化算法的一个分支,思路是用少量「抗体」在解空间里自我繁殖与淘汰,逼近最优参数组合。把它接进 MetaTrader 5,等于让 EA 在每轮优化里少跑无效样本。 原文示例页显示,该主题在 2024 年 9 月 20 日发布,累计浏览 903、评论 47,说明这类非传统优化器在量化交易者里已有实盘验证需求。 开 MT5 后,可在「策略测试器」里把优化模式切到自定义,再挂入 Micro-AIS 的种群迭代逻辑;相比穷举,抗体规模设在 20~50 时,单品种回测耗时倾向下降一个数量级,但过拟合概率可能随种群缩小而上升。外汇与贵金属杠杆高、滑点跳空频繁,任何优化结果都只代表历史样本,实盘前必须做样本外验证。
从抗体到EA:人工免疫系统怎么搬进优化
人体免疫系统靠细胞、组织和器官识别并清除细菌、病毒、真菌等外来物,这套机制在 1980 年代中期就被盯上——Farmer、Packard、Perelson(1986)与 Bersini、Varela(1990)的工作,让人工免疫系统(AIS)在 1990 年代正式成为优化与学习问题的计算模型。 AIS 把问题拆成三组概念:抗原是待优化的输入,抗体是潜在解,杀伤细胞负责在解空间里搜出最优。它不仅能找解,还模拟了免疫的记忆能力——把异常特征和对应应对存下来,供后续任务复用。 Micro-AIS 是 AIS 的轻量改版,只保留抗体这一种个体,在解空间里各自漂移、互不通信,靠突变和选择自适应任务变化。相比传统 AIS 同时跑 B 细胞、T 细胞、细胞因子等全套,Micro-AIS 的实现成本更低,MT5 里写个几百行就能跑。 选哪个看问题规模:简单快速寻优用 Micro-AIS 足够;若解空间崎岖、需高精度,传统 AIS 的复杂模型可能更稳。外汇与贵金属市场高风险,任何优化结果都只是概率倾向,实盘前务必在 MT5 策略测试器用历史数据验证。
「Micro-AIS 的亲和度与突变机制演化」
Micro-AIS 最早用「亲和度」衡量抗体(候选解)与抗原(目标)的相似度,定义为特征向量与权重向量的距离,距离越小亲和度越高。实验里这种搜索策略并不高效,直接用适应度函数值取代亲和度筛选反而更实用,改动只需几行代码就能在 MT5 里验证。 最初的突变概率随适应度增大而降低,实测效率低下也被弃用。现版克隆突变方程:X' = X + dist * rnd * k * mutation。其中 rnd 为 [-1.0,1.0] 均匀随机数,k = (epochs - epochsCNT) / epochs 随迭代递减,令后期参数跳变放缓,提高向最优解收敛的概率。 算法伪代码核心循环:随机布点生成抗体克隆 → 算适应度 → 按递减进度规则(非直接按适应度)给第1、2、3…个抗体派发递减数量克隆 → 克隆基因突变 → 合并亲本与克隆按适应度降序排序 → 选优进入下一轮,直到达到最大迭代或目标适应度。外汇与贵金属参数优化属高风险场景,回测结论仅代表历史样本表现。 下面这段结构定义是整套系统的地基:S_Agent 只存坐标数组 c 和适应度 f,Init 时把 f 置为 -DBL_MAX;C_AO_Micro_AIS 类持有最佳坐标 cB、最佳适应度 fB、个体数组 a 及搜索边界数组,外部参数含 coords、popSize、mutation、epochs 等。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="kw">struct S_Agent { class="type">void Init(class="type">int coords) { ArrayResize(c, coords); f = -DBL_MAX; } class="type">class="kw">double c []; class=class="str">"cmt">//coordinates class="type">class="kw">double f; class=class="str">"cmt">//fitness }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class C_AO_Micro_AIS { class="kw">public: class="type">class="kw">double cB []; class=class="str">"cmt">//best coordinates class="kw">public: class="type">class="kw">double fB; class=class="str">"cmt">//FF of the best coordinates class="kw">public: S_Agent a []; class=class="str">"cmt">//agent class="kw">public: class="type">class="kw">double rangeMax []; class=class="str">"cmt">//maximum search range class="kw">public: class="type">class="kw">double rangeMin []; class=class="str">"cmt">//manimum search range class="kw">public: class="type">class="kw">double rangeStep []; class=class="str">"cmt">//step search class="kw">public: class="type">void Init(const class="type">int coordsP, class=class="str">"cmt">//coordinates number
◍ 克隆变异类的成员与初始化入口
这段声明把一个基于人工免疫系统的优化器骨架摊开了:公开方法只有 Moving() 和 Revision(),其余全是私有状态。种群规模、最小克隆数、克隆步长、变异率、总轮次都作为私有字段缓存,意味着一旦 Init 传参定型,运行期不再从外部改这些超参。 注意 cCnt[] 这个数组,它给每个抗体单独记克隆次数,配合 cloneStep 控制扩增节奏;parents[] 与 pTemp[] 分离,说明父代遴选和临时种群演化是两步走,避免原地覆盖导致排序错乱。 Init 的形参列表和类声明里的 const 入参一一对应:coordsP 决定解空间维度,popSizeP 是种群基数,mutationP 以 double 传入,通常取 0.01~0.2 区间,过大易发散、过小收敛慢。外汇与贵金属行情噪声高,这类参数在实盘前必须用 MT5 策略测试器做多品种回测,高风险品种尤需收紧变异率。 下面这段就是 Init 函数头的真实签名,复制进 MQ5 头文件即可对齐编译器:
const class="type">int popSizeP, class=class="str">"cmt">//population size const class="type">int minClonesNumberP, class=class="str">"cmt">//minimum number of clones const class="type">int cloneStepP, class=class="str">"cmt">//clone step const class="type">class="kw">double mutationP, class=class="str">"cmt">//mutation const class="type">int epochP); class=class="str">"cmt">//total epochs class="kw">public: class="type">void Moving(); class="kw">public: class="type">void Revision(); class=class="str">"cmt">//---------------------------------------------------------------------------- class="kw">private: class="type">int coords; class=class="str">"cmt">//coordinates number class="kw">private: class="type">int popSize; class=class="str">"cmt">//population size class="kw">private: class="type">int minClonesNumber; class=class="str">"cmt">//minimum number of clones class="kw">private: class="type">int cloneStep; class=class="str">"cmt">//clone step class="kw">private: class="type">class="kw">double mutation; class=class="str">"cmt">//mutation class="kw">private: class="type">int epochs; class=class="str">"cmt">//total epochs class="kw">private: class="type">int epochsCNT; class=class="str">"cmt">//epoch counter class="kw">private: class="type">int parentsNumb; class=class="str">"cmt">//number of parents class="kw">private: class="type">bool revision; class="kw">private: S_Agent parents []; class=class="str">"cmt">//parents class="kw">private: class="type">int ind []; class="kw">private: class="type">class="kw">double val []; class="kw">private: S_Agent pTemp []; class="kw">private: class="type">int cCnt []; class=class="str">"cmt">//clone counters for each antibody class="kw">private: class="type">class="kw">double SeInDiSp(class="type">class="kw">double In, class="type">class="kw">double InMin, class="type">class="kw">double InMax, class="type">class="kw">double Step); class="kw">private: class="type">class="kw">double RNDfromCI(class="type">class="kw">double min, class="type">class="kw">double max); class="kw">private: class="type">void Sorting(S_Agent &p [], class="type">int size); }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_Micro_AIS::Init(const class="type">int coordsP, class=class="str">"cmt">//coordinates number const class="type">int popSizeP, class=class="str">"cmt">//population size