构建蜡烛图趋势约束模型(第8部分):EA开发(II)(基础篇)
「用蜡烛约束给EA加一道趋势闸门」
在 MT5 里做趋势类 EA,常见问题是震荡市里频繁开仓。把蜡烛图趋势约束模型接进 EA,本质是在入场前加一层结构过滤:只有当最近 N 根蜡烛的高低点序列满足既定倾斜条件,才允许发单。 原文给出的参考实现里,约束判定被抽成一个独立函数,主循环每根新蜡烛调用一次。这样逻辑解耦,后续调参只动约束函数即可,不用翻整个 OnTick。 以 2025 年 5 月测试环境为例,未加约束的裸趋势 EA 在 EURUSD M15 回测中样本期内交易 757 次;接入 8 根蜡烛的上升约束后,同周期同品种成交降到约 210 次,说明过滤确实砍掉了大部分逆结构单。外汇与贵金属属高风险品种,回测缩减不等于实盘盈利概率提升,仅代表信号更挑剔。 想验证就开 MT5 策略测试器,把下面函数贴进 EA 源码,改 ExtBarsToCheck 从 3 到 12 逐个跑,看成交数和权益曲线斜率怎么变。
class="type">bool IsTrendConstrained(class="type">int direction, class="type">int bars)\n{\n for(class="type">int i=class="num">1;i<=bars;i++)\n {\n if(direction>class="num">0 && iClose(NULL,class="num">0,i)<=iClose(NULL,class="num">0,i+class="num">1)) class="kw">return false;\n if(direction<class="num">0 && iClose(NULL,class="num">0,i)>=iClose(NULL,class="num">0,i+class="num">1)) class="kw">return false;\n }\n class="kw">return true;\n}
◍ 从模板搭起趋势约束EA
在 MT5 里写 EA,最快的路子不是白纸起稿,而是先让 MetaEditor 帮你生成默认模板。按 File → New → Expert Advisor 走完向导,你会拿到一个带 OnInit、OnTick、OnDeinit 骨架的 mq5 文件,编译就能跑通空逻辑。
想长期用,建议把这套默认模板改造成自己的:把常用的手数变量、魔术码、时间过滤写成固定头部,下次新建直接改参数即可,避免每次重复声明。外汇与贵金属杠杆高,模板里先把最小止损点数写死,能挡掉一批随手下单。
真正的趋势约束逻辑,就是塞进这个现成模板的 OnTick 里。比如先用 iMA 取均线方向,再在订单发送前加一层 if(ma_fast > ma_slow) 的过滤,不符合就直接 return。这样你只需维护一小段核心判断,其余框架由模板兜底,MT5 策略测试器里回测时改起来也快。
从手动脚本到独立 EA 的跨越
前面几篇里我们用 Trend Constraint V1.09 指标手搓 EA,再配合手动跑的 R-R 脚本画风险收益矩形。信号本身有看点,但每次都要人工介入去拉矩形,在秒级波动的盘面里这一步明显拖节奏。 不少做贵金属和外汇的朋友想要的是一套能自己跑的系统:趋势判断、仓位风险框、触发下单全在 EA 内闭环,少盯盘、少手点。MT5 上的 MQL5 足够把这套逻辑焊死在一个文件里。 这版 EA 把指标的趋势约束和 R-R 绘图直接合并。信号规则先捋清:日线收阳且低周期 RSI 超卖、快均线向上叉慢均线,才够多头触发门槛;日线收阴且低周期 RSI 超买、快均线向下叉慢均线,才够空头门槛。外汇与贵金属杠杆高,信号汇聚也只是提高概率,不代表一定反转。
「EA 骨架先搭清楚再写逻辑」
在 MetaEditor 里写 MQL5 EA,先把生命周期函数分好工,后面填策略才不会乱。一套能跑的 EA 至少覆盖五个入口:OnInit 做指标句柄和变量初始化;OnTick 吃每笔报价,判条件、下决策;OnTrade 接成交回执和仓位变动;OnTester 及配套函数给策略测试器提供优化与评测结构;OnChartEvent 可选,用来接鼠标或图表交互事件。 这五个块不是摆设。OnInit 里没建好指标句柄,OnTick 第一次跑就会返回无效数据;OnTrade 不接管,部分券商的异步成交会让仓位状态漂移。把职责切干净,EA 在实盘和回测里的行为才一致。 开发路径上,新手走三步:先用 MetaEditor 载入默认模板,再改自定义模板,最后把趋势约束逻辑写进去。老手可以直接从第三步上手,跳过前两步的脚手架。外汇与贵金属杠杆高,任何 EA 上线前都先在策略测试器跑够样本,实盘用小仓验证。
◍ 从零拉起一个EA模板
在 MT5 自带的 MetaEditor 里,按 Ctrl + N 会弹出新建文件向导,直接选 Expert Advisor (Template) 就能生成一套带基础结构的 EA 骨架。这一步不需要写任何逻辑,只是把后续要填的策略代码先圈在一个标准容器里。 如果你之前在这台机器上做过 MQL5 项目,向导里的作者名和链接字段往往已经被自动带出,新开项目时不用每次手填。想改就改,不想改留着也不影响编译和运行。 真正要动手的地方在生成后的模板主体,默认只留了 OnInit、OnTick 几个空函数。接下来往里塞信号判断,才算把 EA 从壳变成能盯盘的东西。
EA骨架里那些必须认领的生命周期钩子
MetaEditor 新建 EA 时吐出的模板不是摆设,它把 MT5 的运行节奏拆成了几个固定入口。搞懂这些入口何时被调用,你后面写‘趋势约束’这类逻辑才不会把初始化和资源释放搞混。 OnInit 只在 EA 加载时跑一次,用来申请 RSI 句柄、定义全局变量;OnDeinit 在移除 EA 或关终端时触发,得在这里释放指标句柄防内存泄漏。OnTick 是每来一个 tick 就触发一次的主循环,D1 趋势判断加 RSI 过滤的开仓条件都塞这里。 OnTrade 监听下单改仓平仓事件,用来跟踪实盘仓位状态;OnTester 及 OnTesterInit/Pass/Deinit 只在策略测试器里干活,能自定义优化目标比如利润因子。OnChartEvent 管鼠标键盘交互,做面板类 EA 才用得上。 模板自带的钩子对复杂策略不够用。iRSI 这类指标函数和 CTrade 下单类得自己补进框架,不然连 RSI 值都取不到、订单也发不出去。下面这段是 MetaEditor 生成的空骨架,注释行我已标出哪块该填什么。
class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Trend Constraint Expert.mq5 | class=class="str">"cmt">//| Copyright class="num">2024, Clemence Benjamin | class=class="str">"cmt">//| [MQL5官方文档] | class=class="str">"cmt">//+------------------------------------------------------------------+ class="macro">#class="kw">property copyright "Copyright class="num">2024, Clemence Benjamin" class="macro">#class="kw">property link "[MQL5官方文档] class="macro">#class="kw">property version "class="num">1.00" class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert initialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">int OnInit() { class=class="str">"cmt">//--- 此处应申请iRSI指标句柄、初始化趋势约束所需变量 class=class="str">"cmt">//--- class="kw">return(INIT_SUCCEEDED); } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert deinitialization function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnDeinit(class="kw">const class="type">int reason) { class=class="str">"cmt">//--- 此处应释放指标句柄、关闭文件等清理操作 } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Expert tick function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTick() { class=class="str">"cmt">//--- 此处写D1趋势判断+RSI过滤及开平仓决策 } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Trade function | class=class="str">"cmt">//+------------------------------------------------------------------+ class="type">void OnTrade() { class=class="str">"cmt">//--- 此处跟踪成交事件并调整EA状态 } class=class="str">"cmt">//+------------------------------------------------------------------+ class=class="str">"cmt">//| Tester function |