种群优化算法:猴子算法(MA)(基础篇)
猴子算法在 MT5 里的种群优化思路
猴子算法(Monkey Algorithm,MA)是一类受种群智能启发的全局优化方法,在 MQL5 的回测与参数寻优场景里,常被用来替代网格遍历,以降低计算开销。它的核心假设是:一组随机初始化的「猴子」在解空间里通过攀爬、观望、跳跃三类动作,逐步逼近更优参数组合。 在 MT5 内置的遗传优化器之外,手动实现 MA 能让你对收敛阈值和种群规模有完全控制权。一个常见设定是种群规模 30、最大迭代 200,在 EURUSD H1 上做均线周期寻优时,相比全网格搜索可节省约 60% 的回测时间,但存在早熟收敛倾向,需配合变异概率调节。 外汇与贵金属品种点差跳变频繁,用该类算法做优化属于高风险实验,实盘前务必在模拟环境复跑验证。
◍ 猴子算法怎么模拟爬山找食
猴子算法(MA)是 R. Zhao 和 W.Tang 在 2007 年提出的元启发式搜索方法,核心灵感来自猴子在山上移动跳跃找食物:山越高、山顶食物越多,于是把适应度函数地形当成山体,最高峰即全局最大化问题的解。 从当前位置起,每只猴子先持续向上爬直到登顶,这一步不断抬高目标函数值;随后向随机方向做局部跳跃,试图撞上更高的山头并再次攀爬。攀爬加局部跳跃循环若干次后,它认为附近地域已探明。 为避免困在本地最优,猴子会做一次长距离全局跳跃,去未知空间重新探索。整个“攀爬—局部跳—全局跳”按参数重复指定代数,种群见过的最高顶点即为输出解。MA 结构简单、可靠性较高,擅长抠出局部最优,但攀登阶段极耗算力。 它的时间主要消耗在攀爬寻局部解,而非像别的进化算法那样铺在广域搜索;这点既是优点也是瓶颈,下一节会拆到表示、初始化与跳跃的具体实现。
「猴子算法怎么在MT5里落地」
猴子算法(MA)的本质是一群代理在搜索空间里乱跳找最高适应度,伪代码里七步循环:随机撒点、测高、局部跳、更好就续跳、局部极限耗尽就全局跳、重复。真正决定收敛质量的不是局部跳,而是全局跳能不能把种群拽出局部极值——实测局部跳对收敛影响很小,全局跳才是脱困关键。 原始 MA 让猴子沿「当前位置—全群几何中心」连线跳,方向可朝中心也可反向。作者在实验中确认:反向跳有约 50% 概率远离全局最优,而跳出中心之外比不跳或反向更有利。团伙不时越过几何中心、整体朝富食区漂移,这种「团伙移动」在动画里清晰可见,原版没有这效果且结果更差。 代码层用 S_Monkey 结构装单只猴子:c[] 当前坐标、cB[] 最佳食物坐标、h/hB 当前与最高高度、lCNT 局部跳计数。C_AO_MA 类里 m[] 是猴群数组,不需要排序,所以方法体都很短。Init() 把最佳品质用最小双精度值初始化;Moving() 首次迭代随机撒点,算 cc[] 坐标中心(算术平均),局部跳半径由 bCoefficient 按维度重算。 全局跳坐标公式 m[monk].c[c] = cc[c] + v[c] * pow(r2, -2.0),r2 取 1~20,这其实是 Levy 飞行:中心附近命中概率高、远处低,平衡探索与开发。越界就折返映射。Revision() 在算完适应度后更新全局解,局部跳要查改善、全局跳不查直接续跳。开 MT5 把下面结构抄进 EA,调 bCoefficient 和猴子数就能跑自己的标的(外汇/贵金属波动大,参数过拟合风险高,建议先历史回测)。
<span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span> <span class="keyword">class="kw">struct</span> S_Monkey { <span class="keyword">class="type">class="kw">double</span> c []; <span class="comment">class=class="str">"cmt">//coordinates</span> <span class="keyword">class="type">class="kw">double</span> cB []; <span class="comment">class=class="str">"cmt">//best coordinates</span> <span class="keyword">class="type">class="kw">double</span> h; <span class="comment">class=class="str">"cmt">//height of the mountain</span> <span class="keyword">class="type">class="kw">double</span> hB; <span class="comment">class=class="str">"cmt">//best height of the mountain</span> <span class="keyword">class="type">int</span> lCNT; <span class="comment">class=class="str">"cmt">//local search counter</span> }; <span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span> <span class="comment">class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————</span> <span class="keyword">class</span> C_AO_MA { <span class="comment">class=class="str">"cmt">//----------------------------------------------------------------------------</span> <span class="keyword">class="kw">public</span>: S_Monkey m []; <span class="comment">class=class="str">"cmt">//monkeys</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> rangeMax []; <span class="comment">class=class="str">"cmt">//maximum search range</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> rangeMin []; <span class="comment">class=class="str">"cmt">//minimum search range</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> rangeStep []; <span class="comment">class=class="str">"cmt">//step search</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> cB []; <span class="comment">class=class="str">"cmt">//best coordinates</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">class="kw">double</span> hB; <span class="comment">class=class="str">"cmt">//best height of the mountain</span> <span class="keyword">class="kw">public</span>: <span class="keyword">class="type">void</span> Init(<span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> coordNumberP, <span class="comment">class=class="str">"cmt">//coordinates number</span> <span class="keyword">class="kw">const</span> <span class="keyword">class="type">int</span> monkeysNumberP, <span class="comment">class=class="str">"cmt">//monkeys number</span> <span class="keyword">class="kw">const</span> <span class="keyword">class="type">class="kw">double</span> bCoefficientP, <span class="comment">class=class="str">"cmt">//local search coefficient</span>
猴群算法的类成员与初始化落点
这套自适应移动平均的优化内核用了一个 C_AO_MA 类,把坐标维度、猴群规模、局部搜索与跳跃系数全部收进私有成员。coordNumber 决定解空间维度,monkeysNumber 是种群规模,bCoefficient 与 vCoefficient 分别控制局部搜索步长和全局跳跃强度,jumpsNumber 限定每次迭代的跳跃次数。 Init 函数承担参数注入和随机数种子重置。MathSrand((int)GetMicrosecondCount()) 用微秒级计时做种子,避免回测时每次跑出同一串伪随机序列;hB 初始化为 -DBL_MAX 表示尚未记录最优适应度,revision 置 false 代表首轮不触发修正逻辑。 数组 rangeMax、rangeMin、rangeStep、b 都按 coordNumber 用 ArrayResize 展开。这意味着你改 coordNumber 前必须确认调用 Init 时传入的维度一致,否则后面寻优会越界报错。外汇与贵金属市场波动剧烈,这类算法参数对过拟合敏感,实盘前建议在 MT5 用历史数据多周期验证。
class="kw">const class="type">class="kw">double vCoefficientP, class=class="str">"cmt">//jump coefficient class="kw">const class="type">int jumpsNumberP); class=class="str">"cmt">//jumps number class="kw">public: class="type">void Moving(); class="kw">public: class="type">void Revision(); class=class="str">"cmt">//---------------------------------------------------------------------------- class="kw">private: class="type">int coordNumber; class=class="str">"cmt">//coordinates number class="kw">private: class="type">int monkeysNumber; class=class="str">"cmt">//monkeys number class="kw">private: class="type">class="kw">double b []; class=class="str">"cmt">//local search coefficient class="kw">private: class="type">class="kw">double v []; class=class="str">"cmt">//jump coefficient class="kw">private: class="type">class="kw">double bCoefficient; class=class="str">"cmt">//local search coefficient class="kw">private: class="type">class="kw">double vCoefficient; class=class="str">"cmt">//jump coefficient class="kw">private: class="type">class="kw">double jumpsNumber; class=class="str">"cmt">//jumps number class="kw">private: class="type">class="kw">double cc []; class=class="str">"cmt">//coordinate center class="kw">private: class="type">bool revision; 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">class="kw">double Scale(class="type">class="kw">double In, class="type">class="kw">double InMIN, class="type">class="kw">double InMAX, class="type">class="kw">double OutMIN, class="type">class="kw">double OutMAX, class="type">bool revers); }; class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void C_AO_MA::Init(class="kw">const class="type">int coordNumberP, class=class="str">"cmt">//coordinates number class="kw">const class="type">int monkeysNumberP, class=class="str">"cmt">//monkeys number class="kw">const class="type">class="kw">double bCoefficientP, class=class="str">"cmt">//local search coefficient class="kw">const class="type">class="kw">double vCoefficientP, class=class="str">"cmt">//jump coefficient class="kw">const class="type">int jumpsNumberP) class=class="str">"cmt">//jumps number { MathSrand((class="type">int)GetMicrosecondCount()); class=class="str">"cmt">// reset of the generator hB = -DBL_MAX; revision = class="kw">false; coordNumber = coordNumberP; monkeysNumber = monkeysNumberP; bCoefficient = bCoefficientP; vCoefficient = vCoefficientP; jumpsNumber = jumpsNumberP; ArrayResize(rangeMax, coordNumber); ArrayResize(rangeMin, coordNumber); ArrayResize(rangeStep, coordNumber); ArrayResize(b, coordNumber);