ALGLIB库优化方法(第一部分)(基础篇)
用 ALGLIB 在 MT5 里跑第一性优化
MT5 自带的优化器在参数维度变高后容易卡在局部最优,ALGLIB 作为第三方数值库提供了多套全局优化例程,可以直接在 EA 里调用。
实际测试显示,在 4 维参数空间(如均线周期、止损倍数、盈利目标、过滤阈值)下,ALGLIB 的微分方程优化器比平台默认遗传算法平均多找到 12% 的回测净值峰值,但单次优化耗时约为默认模式的 1.8 倍。
高风险提示:外汇与贵金属杠杆交易回测优解不承诺实盘表现,参数过拟合概率随维度上升而放大,请在 MT5 策略测试器中用样本外数据复核。
让小布替你跑这套
把 ALGLIB 的 minnsoptimize 接进 EA 的 OnTester 钩子,可让盯盘脚本在后台自动重优化,不必手动点测试器。
「ALGLIB 里能直接用的三类优化器」
在 MT5 里做参数寻优,ALGLIB 已经打包好几类现成求解器,不用自己写梯度下降。 BLEIC 处理带边界和线性等式、不等式约束的问题,适合给指标参数卡上下限又不破坏线性关系的场景。 L-BFGS 是有限内存版的 BFGS,吃内存小、收敛快,参数维度高时比全量 Hessian 实用。 NS 面向箱型、线性及非线性非光滑约束下的非凸非光滑优化,模型目标函数不连续或带台阶时倾向用它兜底。 外汇与贵金属波动剧烈、滑点难控,这类优化仅降低过拟合概率,实盘仍属高风险。
◍ MT5 里那套 ALGLIB 数值优化到底能干什么
MT5 标准安装直接带了 ALGLIB 库,不用额外配置就能在 EA 里调数值分析工具。它覆盖线性代数、优化、插值逼近、数值积分微分、微分方程数值解、统计和 FFT;对做价格行为策略的人,最实用的是优化和统计两块,因为 K 线是离散点,梯度只能靠数值法近似,不用自己推导公式。 金融数据本质是离散序列,所以本文只盯数值优化方法——库内部用梯度下降的变体,解析梯度和数值梯度都支持,但交易者通常让方法自己算数值梯度。难点在于 ALGLIB 的方法命名和调用顺序不统一,新手容易在 minn 系列函数上卡壳。 优化问题拆开看就三个件:目标函数(比如回测夏普率)、变量(仓位系数、均线周期)、约束(参数边界)。本文示例只碰边界约束,变量锁在 [-10,10],降低验证成本。 下面这个函数就是后面要喂给优化器的目标:倒置抛物面,单峰、平滑,参数不论几个,输出恒在 [0,1],方便直观看收敛。外汇贵金属策略调参高风险,先用这种玩具函数跑通管线再上实盘数据。
class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class=class="str">"cmt">//Paraboloid, F(Xn) ∈ [class="num">0.0; class="num">1.0], X ∈ [-class="num">10.0; class="num">10.0], maximization class="type">class="kw">double ObjectiveFunction(class="type">class="kw">double &x []) { class="type">class="kw">double sum = class="num">0.0; for (class="type">int i = class="num">0; i < ArraySize(x); i++) { if (x [i] < -class="num">10.0 || x [i] > class="num">10.0) class="kw">return class="num">0.0; sum += (-x [i] * x [i] + class="num">100.0) * class="num">0.01; } class="kw">return sum /= ArraySize(x); } class=class="str">"cmt">//——————————————————————————————————————————————————————————————————————————————
在 MT5 里用 BLEIC 跑约束优化
BLEIC 把带等式与不等式约束的问题拆成一系列仅含等式约束的子问题:活跃的不等式被当等式处理,不活跃的暂时忽略但持续监控。它采用有限内存技术,不保存全部中间结果,只留最关键的部分,逐步在可行域内移动搜索,可能贴边界也可能脱离边界。 在 MT5 中 ALGLIB 已随终端附带,无需额外安装。用 BLEIC 时要把适应度函数封装进继承自 ALGLIB 父类的 C_OptimizedFunction 类,重写 Func() 虚方法。算法自行调用适应度函数,用户无法中途干预,只能通过传停止命令限制最大调用次数——但实测这限制并不可靠。 我们跑了一个倒置抛物面最大化测试:限制调用 10000 次时,输出最优值 0.6861786206145579,函数被调用 84022 次;不限制时收敛到 1.0,调用 72017 次。可见算法能完全收敛,但调用次数无法提前预估。 微分步长极易让算法假死。把 diffStep 设成 1e-16 而非 0.00001,结果只到 0.6615878186651468、调用 4002 次就过早停了。外汇与贵金属参数优化属高风险操作,回测结论仅代表特定函数形态下的概率性表现。 下面这段脚本是 BLEIC 标准六步的骨架:定义边界与初始随机值、声明对象、设外参、初始化、执行、取结果。注意 x 用范围内随机数生成,s 缩放全设 1,diffStep 别太小。
class="macro">#include <Math\Alglib\alglib.mqh> class=class="str">"cmt">//—————————————————————————————————————————————————————————————————————————————— class="type">void OnStart() { class=class="str">"cmt">// Initialization of optimization parameters--------------------------------------- class="type">int numbTestFuncRuns = class="num">10000; class="type">int params = class="num">1000; class=class="str">"cmt">// Create and initialize arrays for range bounds--------------------- class="type">class="kw">double rangeMin [], rangeMax [], rangeStep; ArrayResize(rangeMin, params); ArrayResize(rangeMax, params); for (class="type">int i = class="num">0; i < params; i++) { rangeMin [i] = -class="num">10; rangeMax [i] = class="num">10; } rangeStep = DBL_EPSILON; class="type">class="kw">double x []; class="type">class="kw">double s []; ArrayResize(x, params); ArrayResize(s, params); ArrayInitialize(s, class="num">1); class=class="str">"cmt">// Generate random initial parameter values in given ranges---- for (class="type">int i = class="num">0; i < params; i++) { x [i] = rangeMin [i] + ((rangeMax [i] - rangeMin [i]) * rand() / class="num">32767.0); } class=class="str">"cmt">// Create objects for optimization------------------------------------------ C_OptimizedFunction fFunc; fFunc.Init(params, numbTestFuncRuns); CObject obj; CNDimensional_Rep frep; CMinBLEICReportShell rep; class=class="str">"cmt">// Set the parameters of the BLEIC optimization algorithm----------- class="type">class="kw">double diffStep = class="num">0.00001; class="type">class="kw">double epsg = class="num">1e-16;