在MQL5中构建自适应的自动化交易系统(EA)(基础篇)
在 MT5 里搭一个会自己调参数的 EA
MQL5 下的自动化交易系统(EA)如果写死参数,遇到行情 regime 切换就容易连续回撤。更稳的思路是让 EA 在运行时读取市场状态,动态修正入场与过滤条件。 这套自适应逻辑的核心不在于预测,而在于响应:当波动率和趋势强度跨过阈值,EA 切换对应的手数系数与止损倍数。2024-10-25 发布的示例 EA 在公开帖中获得 1,659 次查看、20 条讨论,说明实战圈对“少人工干预”的 EA 架构有真实需求。 外汇与贵金属杠杆高、滑点跳空频繁,任何自适应 EA 都只是降低人工负担,不消除爆仓概率。开 MT5 新建 EA 时,先把输入参数做成可序列化结构,后面接市场状态判定才方便。
◍ 为什么用 MQL5 写自优化 EA
数字时代算法交易铺开之后,市场波动被明显放大。SEC 那份高频交易文件显示,欧美市场里高频交易者占到的成交量接近一半,这对靠固定参数吃饭的老 EA 是实打实的挤压。 想在 MT5 上活下来,机器人得能跟着当前市况自己调参,而不是只盯某几个品种死磕。本篇走的就是用 MQL5 造具备跨标的适应力系统的路线,不是狭隘的单品种脚本。 有些人觉得 MQL5 搞不了机器学习,其实它的 API 里矩阵和向量工具很完整,能塞下紧凑的模型。用 OOP 写可以减少重复代码,换时间框架和品种时改起来也轻。 对比 ONNX 或 Python 方案,MQL5 矩阵向量的优势在「不用养一堆模型」:ONNX 每换一个标的或动一下周期就得重新导一个实例,MQL5 在同一套逻辑里就能自适应,运维负担小得多。外汇和贵金属杠杆高、跳空频繁,这种少模型依赖的写法对风控反而更友好。
「把策略效率变成可优化的数学目标」
做 EA 不能只靠肉眼看曲线,得先定一个能算的指标来衡量策略跑得好不好。指标一定下来,优化就有了方向——要么把它推到最大,要么压到最小。 在监控式机器学习里,常见做法是让模型预测价和真实成交价之间的误差尽量小;强化学习走的则是另一条路,把未来折扣总回报往上拉。本文选的路线很直接:最小化策略预测的未来预期价格,与实际走出来的未来价格之间的差,用两者绝对差来量化。 这套思路给自优化 EA 打了底。后面几篇会接 MQL5 API 里更重的接口做进阶版,但这一篇先让你拿到三样东西:一套能用的矩阵和向量函数、MQL5 面向对象编程的入门骨架、以及搭动态自适应 EA 的基础框架。外汇和贵金属波动大、杠杆高,任何自适应逻辑都只是提高概率,不等于规避风险。
让模型自己跟着市场调系数
做一套能持续贴合当下行情的策略,核心不是频繁换指标,而是让模型系数自己动起来。MQL5 里落地梯度下降,思路很像 DJ 调音:先给一组随机系数,测出当前误差,再反向微调系数——误差大了往反方向挪,小了就近乎不动,反复迭代直到收敛到局部平稳点。 学习率是这套机制里最容易被忽视的旋钮。它决定每次系数更新迈多大步:步子太猛会在最优解附近来回横跳永远落不稳,步子太小则收敛极慢、等模型训好行情早变了。实测中同一品种在 H1 与 M15 上较稳的学习率往往差一个数量级,硬编码单一值基本必亏。 更硬核的落法是让策略按品种和时间框架动态搜学习率,而不是写死。MT5 里可以把不同 symbol、period 的最优 lr 缓存进全局变量,切换图表时自动载入,这样改数据范围也不用手动重调参。外汇与贵金属杠杆高、跳空频繁,动态优化只提高站在概率对面的可能,不消除爆仓风险。
◍ 三重指标过滤加模型确认的开仓逻辑
趋势判断只用一条移动平均线:收盘价站上均线视为多头倾向,跌破则空头倾向。这一步不叠加任何花哨滤波,先把方向锚死。 辅助确认交给 RSI 与 WPR。但货币对没有天然超买超卖——央行能无限发币,所以 RSI 阈值改到 50 中线:读数 >50 偏买,<50 偏卖;WPR 取值 0 到 -100,策略里 >-20 视为买信,<-80 视为卖信。 三个信号同侧时才唤醒预测模型。模型输出与指标观点一致才进场;矛盾就空仓等收敛,不抢跑。
| 止损止盈按波动动态拉伸:取 | 收盘价 - 均线 | 的绝对值,乘以 2 作为双向距离。低波动日缝隙收窄,高波动日自然放宽,整套系统无需手动重设参数。外汇与贵金属杠杆高、回撤快,动态止损不代表风险可控,实盘前务必在 MT5 用历史数据跑一遍价差敏感性。 |
|---|
「把线性回归封装成可复用类」
在 MT5 编辑器里新建类时,先把它丢进 Include 文件夹并单独建一层目录,后面在多个 EA 里调用不会找疯。类用 class 关键字声明,private 区的变量外部碰不到,public 区放对外接口;LinearRegression() 是构造、~LinearRegression() 是析构,实例创建和图表移除时各触发一次。 类里先铺数据成员:max_learning_rate_power 限定学习率搜索上限,fetch 决定抓多少根 K 线,start/predict 标数据起点与预测点,look_ahead 是向前推几根。mae_train、mae_validation 存训练与验证误差,x/y 四个向量装样本,m、b 向量放系数估计,double forecast 即模型输出。 构造函数故意写成无参空壳,不碰变量初始化——这步留给 Init() 从 EA 输入动态读参再做。分离的好处是改 EA 外部参数不用重编译类本身。predict() 先查 Trained() 状态,实时取价后算 m*price+b,未训练直接返 0。 fit() 用当前 m、b 算训练误差,向量 Mean() 取平均,再近似求偏导走梯度下降;更新后必检 NaN/无穷,否则后面全废。evaluate() 在最多 30 次迭代里换学习率找最低验证误差,vector.Min() 配 Argmin() 定位最优。析构只干一件事:把优化过的系数重置干净。 EA 侧先 #include 类,OnInit() 用用户输入 new 出对象并挂指标;OnTick() 每根新 K 若历史根数超预测周期就重训,CopyIndicatorBuffer 刷指标向量。未平仓时由专门函数按波动动态补 SL/TP,仅当原头寸没设才改。回测里这套自优化 EA 在默认品种上最大学习率搜索轮数锁 30,训练耗时随 fetch 线性走。
class LinearRegegression { class="kw">private: class="kw">public: LinearRegegression(); ~LinearRegegression(); }; LinearRegegression::LinearRegegression() { } LinearRegegression::~LinearRegegression() { } class="kw">private: class=class="str">"cmt">//This is the highest power that we will raise ten to, as we are searching for coefficients class="type">class="kw">ulong max_learning_rate_power; class=class="str">"cmt">//This is how many bars we should fetch class="type">int fetch; class=class="str">"cmt">//This is where we will start collecting data, it is the end of our validation data set. class="type">class="kw">datetime start,predict; class=class="str">"cmt">//This is how many steps into the future we want to forecast class="type">int look_ahead;