ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

MT4 EA自动交易系统实战:从EA逻辑选型到回测校准与实盘风控

MT4 EA自动交易系统实战:从EA逻辑选型到回测校准与实盘风控

简介:MT4自动交易系统(EA)策略包汇集了多套市场常见策略,面向希望借助算法辅助决策的外汇交易者,也适合有一定MQL4基础、想研究现成代码的进阶用户,帮助读者理解EA的适用边界与常见误区。内容涵盖自动交易的机制与优势、EA编写与安装方法、回测优化及风险管理要点,并配有交易纪律、亏损认知等辅助文档,可帮助读者避免盲目依赖自动化,建立稳健的EA使用思路。压缩包共151个文件,主体为53个mq4策略源码和51个ex4编译成品,另含doc交易规则文档、tpl图表模板、rar/zip打包的多套策略合集及少量辅助文件,整体约17MB,按策略类型分区存放,文件名与目录划分清晰,便于查阅、对比和二次开发。该资源已有近千人学习下载,适合先在模拟账户中测试验证,再通过对照源码与文档理解经典EA的设计逻辑,逐步形成自己的交易系统。

1. MT4自动交易系统:为什么装上EA不等于躺赚

MT4里的自动交易系统,通常被称为EA(Expert Advisor)。多数人手里的第一个EA不是自己写的,而是从群聊、论坛或者某个源码包下载来的“稳定盈利”版本。装上之后第一件让人意外的事往往是:回测曲线漂亮得不像真的,实盘账户却在两周内把利润吐了回去。这不是EA本身“有诈”,而是自动交易系统的运行环境比大多数人预想的苛刻许多——点差、滑点、执行速度、平台设置、数据精度,任何一个环节的偏差都会改写最终结果。

下面这条路线是我自己做自动交易时反复走的:先认识几类最常跑的EA逻辑,再把它装进MT4、做好参数校准,用策略测试器验证,最后挂到实盘上持续观察。新手能照着把第一个EA跑起来,熟手能回来检查自己的参数和验证习惯。记住一个前提:自动交易系统的价值是纪律,不是“一键躺赚”的承诺。

2. 三种EA逻辑的选型边界:网格、突破与双均线,哪个值得跑

标题里“几个自动交易系统”,关键在“几个”背后的逻辑分类。EA千千万,绝大部分可以归为三类:网格、突破、趋势跟随。分别对应“震荡市里的往返”“单边启动的瞬间”“趋势延续的过程”。选哪一种,取决于你想在什么行情里赚钱,以及你能不能接受它在相反行情里的亏损方式。很多新手上来就下载几十个EA,全部挂上图表,结果账户里订单交错、方向互相打架。我一般建议:先选定一种逻辑,把它的边界摸清楚,再考虑多品种或者多策略组合。下面三种是我自己跑过、也见过别人跑过的主力类型。

2.1 网格EA:震荡里的盈利机器,单边行情里的定时炸弹

网格EA的逻辑很直白:以当前价格为基准,每隔固定间隔挂一张买单和一张卖单;价格下跌一层,买入一张,反弹到网格上一格止盈;价格上涨一层同理。它赚钱的前提是价格在区间里来回摆动,每一轮摆动收割一格利润,持仓方向永远在市场当前价格附近。听起来很美,但它的生存条件很窄:一旦价格走出单边行情,网格会沿着错误方向持续加仓,账户浮亏越来越大,直到保证金不足被强平。

参数是网格EA的命门。常见做法是三个数字:网格间距、单笔手数、最大持仓单数。间距决定了震荡市里触发的频率,间距太小会频繁加仓,实盘点差成本会吃光网格利润;间距太大又变成“长期不交易”。手数要注意多数网格EA采用固定手数,而不是倍增——倍增网格在历史回测里曲线很漂亮,实盘里它把“浮亏”变成了“爆仓”的加速器。最大持仓单数必须写死,哪怕你心里预期行情不会走多远。我的习惯是:黄金用200点间距起步,最大单数不超过10,单笔手数不超过账户净值的2%。

2.2 突破EA:用ATR过滤假突破,参数就三四个

突破EA做的是“价格突破N周期高低点后进场”的动作。逻辑基础是:当价格突破了之前一段时间的运行区间,说明原有的多空平衡被打破,新的趋势可能开始。这种策略在趋势行情里有天然优势,但横盘震荡阶段会被反复打脸——每次突破都是假的,EA追进去就反向。

所以成熟的突破EA会加一道过滤:直接用当前周期的ATR值作为突破有效性的门槛。例如,收盘价高于前N根K线的最高价,且突破幅度大于1倍ATR,才开仓;同时把止损放在突破区间的另一侧。这样做的好处是把“假突破”筛掉一部分,坏处是会让你错过一部分贴着边界刚突破就拉走的行情。ATR过滤倍数设小一点,比如0.8,交易次数多一些但单次亏损小;设到1.5以上,交易次数明显变少,但单笔质量更高。我用的时候通常会搭配一个更高周期的趋势判断,比如1小时图突破只在4小时图方向一致时执行,过滤效果比单纯调ATR明显。

2.3 双均线EA:最适合入门的最小实现,代码从这一份改起

双均线是趋势跟随里最朴素的一种:快线从下方穿越慢线做多,从上方穿越做空。它的优点是没有复杂的行情假设,也不会频繁加仓,每一笔交易独立止损,逻辑一眼能看懂。缺点同样明显:在震荡区里反复穿越,小亏一直累积。对入门者而言,双均线是最适合先把“加载、回测、实盘”全流程走一遍的EA类型。

下面是一份最简可编译的MQL4骨架代码。它只做一件事:按照两根均线的交叉信号判断最新K线状态,在已有持仓未平仓时不重复开仓:

//| 双均线交叉示例EA,仅供学习MQL4骨架 #property strict input double InpLotSize = 0.01; // 固定开仓手数 input int InpFastMA = 5; // 快线周期 input int InpSlowMA = 20; // 慢线周期 input int InpSLPoints = 300; // 止损点数,0为不设 input int InpTPPoints = 600; // 止盈点数,0为不设 input int InpMagic = 20240101; // 魔术数字,隔离本EA的单 input bool InpUseStop = true; // 是否启用止损止盈 void OnTick() { // 只检查本EA自己的单子,避免干预手动单 for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderMagicNumber() != InpMagic) continue; if(OrderSymbol() != Symbol()) continue; return; // 已有持仓,本周期不再重复开仓 } double fastPrev = iMA(Symbol(), 0, InpFastMA, 0, MODE_SMA, PRICE_CLOSE, 1); double fastCurr = iMA(Symbol(), 0, InpFastMA, 0, MODE_SMA, PRICE_CLOSE, 0); double slowPrev = iMA(Symbol(), 0, InpSlowMA, 0, MODE_SMA, PRICE_CLOSE, 1); double slowCurr = iMA(Symbol(), 0, InpSlowMA, 0, MODE_SMA, PRICE_CLOSE, 0); // 金叉:快线从下往上穿过慢线 if(fastPrev <= slowPrev && fastCurr > slowCurr) OpenOrder(OP_BUY); // 死叉:快线从上往下穿过慢线 else if(fastPrev >= slowPrev && fastCurr < slowCurr) OpenOrder(OP_SELL); } void OpenOrder(int cmd) { double price = (cmd == OP_BUY) ? Ask : Bid; double sl = 0, tp = 0; if(InpUseStop) { sl = price - InpSLPoints * Point; tp = price + InpTPPoints * Point; if(cmd == OP_SELL) { sl = price + InpSLPoints * Point; tp = price - InpTPPoints * Point; } } int ticket = OrderSend(Symbol(), cmd, InpLotSize, price, 3, sl, tp, "SimpleMA EA", InpMagic, 0, clrNONE); if(ticket < 0) Print("开仓失败,错误码: ", GetLastError()); }

代码里最关键的是两个输入参数:InpFastMA 和 InpSlowMA。快线周期越小,信号越灵敏,在震荡行情里会频繁进出;慢线周期越大,趋势识别越迟钝,但也越不容易被短波动干扰。InpSLPoints 和 InpTPPoints 用点数表示,1点对应当前品种的 Point,黄金和欧美货币对应的实际距离差异很大,所以这两个参数应该按品种分别调,不要一套参数通吃所有图表。InpMagic 的作用是给本EA的单子打标记,后面无论是平仓、统计还是加仓判断,都靠这个数字区分,绝不共用。

3. 把一个EA放进MT4:加载路径、参数面板与运行前检查

选好逻辑、手上有了一份.mq4源码,接下来的问题是怎么让它跑起来。很多人的第一反应是直接双击源码文件,结果MT4毫无反应。原因是MT4里的EA并不是独立程序,它必须待在固定的目录里、经过编译器生成.ex4文件,再被加载到图表上才会工作。这一章把从“源码到实盘运行”的完整路径走一遍。

3.1 文件放对位置,编译通过,列表里才会出现

MT4安装目录下有一个 MQL4 文件夹,自动交易系统的源码放在 MQL4\Experts 里。把.mq4文件复制进去后,打开MT4自带的MetaEditor,在导航器窗口刷新一下,文件才会出现在“智能交易系统”列表里。选中文件按F7编译,底部出现“编译成功”且不报error,才会生成同名的.ex4文件。编译失败的常见原因是源码里用了第三方库没有一并放进来,或者代码的MQL4版本语法和你安装的MT4版本不兼容。

编译通过后回到MT4主界面,把EA从导航器列表里直接拖到想运行的图表上,弹窗里勾选“允许实时自动交易”,确定。注意:如果图表右上角出现的是笑脸图标,说明EA正在运行;如果图标上有禁止符号或者显示为空白,说明还没成功挂载,需要查看“智能交易系统”标签页里的日志。

3.2 参数面板里的每一栏分别控制什么

大多数EA在加载弹窗里都有“输入参数”标签页,这一页决定EA在实盘上的行为。下表以常见的趋势EA为例列出必看的几项:

参数名起始建议作用常见错误
手数0.01每笔开仓的仓位大小实盘一上来就调大,亏损远超预期
快线周期5信号灵敏度周期太小,震荡里来回开平
慢线周期20趋势级别两线太近,信号过密
止损点数300单笔最大亏损距离设为0等于不设止损
止盈点数600单笔止盈距离与止损比例失调,盈亏比失衡
魔术数字随机数识别本EA的单子与手动单或其他EA冲突
最大持仓数无限制同时持有的单量缺失时网格类EA容易失控

加载前,每一项都要知道它是干什么的,而不是全部保持默认。手数尤其要谨慎,回测时用1手跑出来的收益曲线,实盘挂0.01手可能连续几个月看不到明显变化;反过来,回测里1手的回撤,实盘换成5手就是爆仓级别的风险。

3.3 加载前对照:品种符号、杠杆与时区三重匹配

第一重是品种符号。源码里如果用字符串固定写死“EURUSD”,当你把它拖到“XAUUSD”图表上时,EA要么不开单,要么在错误的品种上交易。我一般会要求自己写的EA内部用 Symbol() 动态获取当前图表品种,而不是硬编码。第二重是杠杆。同一账户下,欧美货币对和黄金的保证金占用差异很大,回测时选的杠杆比例和实盘账户不一致,所有基于百分比的风控数值都会偏。第三重是服务器时区。MT4里 K线开盘时间和服务器时区绑定,如果你在EA里写了“只在晚上9点后交易”这类时间过滤,务必要确认过滤用的是 TimeCurrent() 和服务器时间,而不是你本机的时间。

也有一个很实用的小检查:在EA加载后,打开“智能交易系统”日志,看有没有初始化成功的提示。没有初始化成功消息的EA,就算界面显示笑脸也大概率没跑起来。如果你发现日志里反复出现“stopped because of market closed”,说明EA逻辑本身要等市场重新开盘才会继续,不一定是故障。

4. 策略测试器回测:数据校准后再信那条曲线

回测是EA能不能上实盘的过滤器。但很多人对这个步骤的理解停留在“跑完曲线好看就行”,忽略了MT4策略测试器里几个会影响结果的关键选择。这一章的目标是让你跑出一条接近实盘的曲线,而不是一条“只有回测里存在”的曲线。

4.1 回测模型三选一,默认的那个最不准

MT4策略测试器提供三种回测模型:每个即时报价、控制点、开盘价。默认的“开盘价”模型速度最快,它假设每一根K线只在开盘价成交,信号判断也只看K线收尾状态,实际运行起来跟真实tick流的差距非常大。控制点模型每分钟生成一个价格点,速度中等,适合快速筛选参数。“每个即时报价”最接近真实盘面,它会按照历史tick数据逐笔判断信号和成交,结果最可信,但速度最慢。

对一个准备实盘的EA,我会要求必须用“每个即时报价”跑,并且把“点差”设置调得比平时略大。比如你常用的平台欧美点差平均是0.8个点,我会在回测里设1.5个点,给滑点和波动留出余地。首次使用某个品种时,还要先在“历史数据中心”把M1数据完整下载下来,tick数据缺失的时段在日志里会显示,这些区域的回测结果是没有参考价值的。

4.2 用基准参数先跑一轮,只看四条统计量

参数调优之前,先用一套“不花哨”的基准参数跑一轮完整回测。所谓基准,就是去掉各种过滤器,用固定的手数、常规的周期和止损。这个结果代表策略的原始面貌。回测报告里数据很多,我通常只看四条:

统计量参考线说明
交易次数至少30次次数太少,结果没有统计意义
净利润正数负的连交易成本都覆盖不了
最大回撤50%以内超过说明仓位或止损逻辑有问题
获利因子大于1.2小于1说明策略本身不盈利

如果基准参数下交易次数太少,先不要急着优化,而是检查信号是否过于稀疏——可能是周期选得太大,或者过滤条件太严。如果回撤巨大,先调止损和手数,而不是换一组参数。曲线的“平滑度”不是重点,重点是你是否能说清楚每笔亏损来自什么行情,以及连续亏损期间账户能否扛住。

4.3 优化器会骗人:参数平原比参数尖峰可靠

策略测试器自带的优化功能,本质上是在历史数据上做参数搜索,找出使净利润最大的那一组参数。它有一个很难绕开的陷阱:历史数据里既包含了真实的行情规律,也包含大量随机噪声,优化器会把噪声当成规律一起拟合进去。最常见的结果,就是优化出一组在某个时间段内漂亮的参数,换个时间段立刻失效。

判断参数是否可靠,一个简单办法是看“参数平原”。把优化出的最优参数周围的几十组参数全部跑一遍,如果只有最优值附近狭窄的一个点赚钱,旁边全部亏损,这是典型的过拟合尖峰,直接放弃;如果以最优参数为中心、相邻的一大片参数都能盈利,说明策略本身对参数不敏感,这种结果才更接近真实。我自己的习惯是:只用完整枚举或遗传算法做二维参数优化,三维以上参数的“最优组合”,在实盘里大概率只是刚好匹配了一段历史行情。

5. 实盘避坑:EA跑飞前的5个典型翻车点与排查顺序

到了这一章,你和一套EA之间只隔着实盘。这里的每条记录,都是我自己或者身边做交易的人真实踩过的坑。把它们按顺序检查一遍,可以省下不小的学费。按“现象、原因、解决”来看,每一类都有清晰的排查路径。

5.1 回测盈利、实盘亏损:点差和滑点在天平另一端

现象:同一套参数,回测里稳定盈利,实盘挂上去之后每笔单子都比回测的成交价差十几个点,小止损单频繁被扫。原因:回测用了“控制点”或者“开盘价”模型,点差设置太低,完全没有模拟滑点;实盘的浮动点差和成交延迟在每笔交易上都多付出成本,小周期EA的交易频率越高,这个损耗越明显。解决:回测切到“每个即时报价”,点差按平时水平的1.5到2倍设置,并统计一下自己常用品种在重要数据时段的平均点差,而不是只看平淡时段的报价。

5.2 加载了不交易:魔术数字与品种符号指错了单

现象:EA图标正常,日志里也没有报错,但账户里就是没有新订单。原因:这类问题多出在持仓判断逻辑上。一些EA在开仓前会先检查“是否已有持仓”,检查条件里用了固定的品种字符串或者没有匹配魔术数字,导致EA认为“已经有单子了”,实际那单可能是你手动开的,或者另一个EA开的。解决:确认品种判断全部用 Symbol() 动态获取;给每个EA分配独立的魔术数字;如果你看不懂源码里的持仓检查逻辑,写一行Print输出当前位置的持仓数量,确认查询条件返回的是不是0。

5.3 网格EA在单边里连环加仓:缺了三个硬约束

现象:震荡期账户非常平稳,某天来了一波单边行情,网格像套娃一样一档一档加仓,浮亏从小变大,最后触发强平。原因:网格EA的回测数据多取自震荡占主导的区间,设计时没有考虑单边行情;源码里缺少最大持仓单数、偏离基准的最大距离、总浮亏上限三个约束的任何一个,都会在单边里失控。解决:跑回测前先把K线数据时间范围拉长到包含至少一段明显的单边趋势,观察这期间的最大持仓数和最大回撤;实盘参数里必须把最大持仓单数写死,并设定“价格偏离基准超过N倍ATR后停止继续加仓”。

5.4 优化出来的漂亮曲线:过拟合与前置测试

现象:优化后的参数回测年化收益率翻倍,追进去实盘连续亏损,一查才发现“最优参数”只在特定的历史年份有效。原因:优化器在历史数据上找了最匹配噪声的参数组合,这种参数在现实行情中没有稳定性。解决:用前面说过的“参数平原”筛选;选定参数后做一次前置测试,即把参数固定下来,往前滚动一个时间段再跑一遍,看是否还能盈利;如果前置测试明显变差,说明策略对参数过度敏感,宁可不实盘。

5.5 重启后EA罢工:自动交易开关与启动时机

现象:某天发现MT4重启后EA图标还在,但一直不开单;查看日志才发现从重启那一刻起,EA实际上没有调用过信号逻辑。原因:MT4顶部工具栏的“算法交易”按钮被系统设置关闭了,或者程序端启动时处于只手动交易模式,EA被加载但不启用。解决:加载EA后,确认顶部按钮处于开启状态,图标不应该显示为灰色或禁止符号;在平台设置里勾选“允许自动交易”;如果你在非交易时段加载EA,等下一根K线开盘后再检查一次日志,确认EA确实开始了新的运行周期。这一步看似简单,却是实盘里最容易翻车的地方。

6. 进阶:给EA加风控层,再让它按规矩跑多品种

走到这一步,说明你已经能让一套EA稳定地在单个品种上运行了。接下来值得做的不是继续找“更厉害”的EA,而是给现有EA加一层账户级别的风控。因为再精细的信号逻辑,也架不住一笔单子扛着整个账户的风险。

6.1 一个回撤熔断函数:账户级止损是第一道防线

很多EA的止损是“单笔级别”的,这不够。更可靠的做法是监控账户净值的回撤幅度,超过阈值就平掉本EA的所有仓位并停止开新单。下面这个函数可以插入任何一份EA的 OnTick 开头:

double MaxDrawdownPercent = 20; // 账户回撤熔断线,单位% double g_equityStart = 0; void CheckDrawdown() { if(g_equityStart == 0) g_equityStart = AccountEquity(); double ddPercent = (g_equityStart - AccountEquity()) / g_equityStart * 100; if(ddPercent >= MaxDrawdownPercent) { CloseAllThisEAPositions(); Print("触发账户回撤熔断,当前回撤: ", ddPercent, "%"); // 熔断后可以再写一行代码禁用EA,直到人工干预 } } void CloseAllThisEAPositions() { for(int i = OrdersTotal() - 1; i >= 0; i--) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderMagicNumber() != InpMagic) continue; if(OrderSymbol() != Symbol()) continue; if(OrderType() == OP_BUY || OrderType() == OP_SELL) { bool ok = OrderClose(OrderTicket(), OrderLots(), OrderType() == OP_BUY ? Bid : Ask, 3); if(!ok) Print("熔断平仓失败: ", GetLastError()); } } }

把这个函数放在 OnTick 最前面,每个tick都会先检查,而不是等亏损订单自己触发止损。g_equityStart 取的是EA加载当日的账户净值,所以它衡量的是EA运行期间的回撤,而不是账户总资产的历史高点。阈值建议从15%到20%起步,太小的阈值在正常波动下就会频繁熔断,打断策略本身。

如果你想同时把这套EA挂到多个品种,记得每个图表单独分配一个魔术数字段,比如欧美用20240101、黄金用20240102,否则任何一个平仓函数都可能误平另一张图表的单子;同时给每个品种单独做一轮回测,别指望一套参数通吃所有品种。

6.2 一周一小检,一月一复盘:验证习惯决定EA能跑多久

实盘跑起来之后,最容易放松的就是检查和记录。我的习惯是每周五收盘后看一下“智能交易系统”日志,记录当前净值、回撤和持仓数,确认没有异常报错。每个月把成交记录和回测报告做一次对比,重点看三个偏差:实际点差与回测点差的差距、滑点出现的频率、每月交易次数是否接近预期。交易次数明显偏少通常说明行情状态变了,不是EA坏了。

我以前也迷信过回测里那种完美曲线的诱惑,总觉得参数优化到位就万事大吉。后来在一次单边行情里看着网格EA一层层加仓、净值一路下滑,才明白自动交易系统真正拼的不是信号有多巧妙,而是风控和验证习惯有多扎实。你现在花在回测校准和风控上的时间,实盘都会以“少亏”的方式回报。希望帮到你。

本文还有配套的精品资源,点击获取

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进