从回测到实盘:MT4 EA稳定运行的五个关键配置细节
上周一个做手工交易的朋友半夜给我发消息,说他挂了个马丁格尔EA在MT4上,结果早上起来一看,单子全乱套了——该开的没开,不该平的全平了,持仓里还多了几个莫名其妙的挂单。他截图给我看,我一眼就发现问题了:EA里用的订单注释和魔术数字跟他手动开的单子混在了一起,再加上他电脑时区跟经纪商服务器时区没对齐,导致EA判断K线收盘的时机全错了。

这种事我见得太多了。很多人以为把EA往MT4图表上一拖,点个自动交易按钮就万事大吉。实际上,MT4的EA部署涉及环境、参数、风控、日志四个层面,任何一个环节没处理好,回测里再漂亮的曲线到了实盘都会变形。今天我就把这几层拆开讲,你照着做,至少能避开九成的低级故障。
第一步:先搞清楚你的经纪商时区,再谈EA逻辑
MT4服务器的时间不是统一的。大部分经纪商用的是UTC+2或UTC+3(夏令时会切换),但有些小众平台直接用UTC+0。你的EA里如果写了「在每天16:00平仓」或者「只在亚洲时段开单」,用的到底是哪个时区?我见过太多人把本地电脑时间写进EA逻辑,结果冬令时切换后,整个策略的执行窗口偏移了一两个小时。
正确做法是:在EA初始化函数里调用 TimeCurrent() 来获取服务器当前时间,所有时间判断都基于这个值。别用 TimeLocal(),那是你电脑的时间。另外,如果你用 iTime() 读取K线开盘时间,记得它返回的也是服务器时间。我在给朋友排查时发现,他的EA里写的是「当H1收盘价高于MA20时买入」,但他用的是 Close[1] 而不是 iClose(NULL, PERIOD_H1, 1),导致他实际判断的是当前未收盘K线的实时价格——这在复盘里没问题,实盘里就会频繁出现信号闪烁。
常见错误:在 start() 函数里直接写 if (Hour() == 16),这个Hour()返回的是服务器小时,但很多人误以为是本地时间。建议统一封装一个 IsTradingSession() 函数,内部用 TimeHour(TimeCurrent()) 判断,这样后续维护时改一处就行。
订单管理:魔术数字和注释是EA的生命线
MT4里区分订单归属,靠的是 magic number(魔术数字)和订单注释。你的EA开单时必须设置一个唯一的魔术数字,比如 MagicNumber = 20251107。平仓、修改止损、统计盈亏时,都要用 OrderSelect() 配合 OrderMagicNumber() == MagicNumber 来筛选订单。如果你同时跑两个EA,或者手动单和EA单混在一起,没有魔术数字隔离,EA平仓时会把你的手动单也一起平掉。
我见过一个极端案例:某个EA在平仓时用的是 OrderClose(OrderTicket(), ...) 直接平所有持仓,结果把用户另一套对冲EA的单子也扫了。正确写法是遍历持仓时先判断魔术数字和订单符号,再决定是否操作。另外,订单注释也别空着,建议写成 "EA名称_版本号_开单时间",这样在MT4终端里一眼就能看出哪些单子是哪个EA开的。
注意:如果你用 OrderSend() 开单后没有立即检查返回值,而是直接继续执行后续代码,很容易出现重复开单。MT4的OrderSend是异步的,返回的ticket可能为-1,你需要判断 ticket > 0 才继续。我习惯开单后加一个 Sleep(100) 再查询订单状态,虽然不优雅,但能避免不少竞态问题。
回测数据里藏着魔鬼:参数区间和滑点设置
很多人跑回测时只看最终盈利因子和最大回撤,却忽略了「参数敏感度」。我测试一个双均线EA时,默认参数下盈利因子1.8,最大回撤12%。但我把均线周期从20改成22,盈利因子直接掉到0.9。这说明策略对参数很敏感,实盘里行情波动一变,参数可能就失效了。所以回测时要做参数扫描——用MT4的策略测试器,把均线周期从10到30逐步递增,步长设2,看盈利因子和回撤的分布。如果参数在某个区间内表现稳定(比如15-25之间都盈利),那才值得实盘。
滑点设置也是个大坑。MT4回测默认滑点可以设为0,但实盘里黄金和交叉盘在数据发布时滑点10-20个点很常见。我在回测里把滑点设成20个点后,盈利因子从1.6降到了1.2。建议你回测时至少用两种滑点设置:一个保守(10点),一个激进(30点),看策略是否还能存活。另外,MT4回测的「每根K线最小价格变化」默认是0.1,如果你做的是头皮类EA,建议把这个值调成0.01,否则回测结果会过于乐观。
我自己的习惯是:回测时间跨度至少覆盖一个完整的趋势周期(比如从2020年到2024年),包含震荡和单边行情。只跑最近三个月的回测,参数很容易过拟合。
VPS部署与断线重连:实盘和回测的分水岭
EA跑在你自己电脑上,一旦关机或者网络断线,就等于裸奔。我见过有人用家用电脑跑EA,结果晚上停电,止损没触发,第二天起来账户亏了20%。正规做法是部署在VPS上,选择离经纪商服务器近的机房。以Exness为例,它的MT4服务器在伦敦和纽约都有节点,你VPS选伦敦的延迟通常在5-10毫秒,选香港的可能要150毫秒以上。延迟高不是致命问题,但如果你做的是日内高频策略,延迟会直接影响成交价格。
VPS配置不用太高,2核4G内存的Linux服务器足够跑三四个EA了。但要注意MT4是Windows程序,你得用Wine或者直接选Windows VPS。我用的是Windows Server 2019,2核4G,跑四个EA加一个MySQL数据库做记录,CPU占用率一般在30%左右。内存别省,MT4本身吃内存,再加上日志和图表,4G是最低配。
断线重连是另一个高频故障。MT4自带的自动重连机制不太可靠,我写了个心跳检测脚本,每30秒检查一次 TerminalInfoInteger(TERMINAL_CONNECTED),如果断开就调用 RefreshRates() 并重新发送挂单。另外,EA里所有止损止盈单不要用 OrderModify() 反复修改,那样会消耗服务器请求次数,容易被限流。我一般只在价格变动超过一定阈值时才修改止损。
一个容易被忽略的细节:点差和合约乘数
不同经纪商的品种合约规格不一样。同样是黄金,XM的MT4上1手是100盎司,Exness的MT4上1手也是100盎司,但点差和保证金计算方式有差异。如果你的EA里写死了止损点数,比如固定止损50点,在XM和Exness上实际亏损金额可能差出20%。所以EA里所有止损止盈都应该基于ATR(平均真实波幅)动态计算,而不是写死点数。
我写过一个简单的ATR止损代码:
double atr = iATR(NULL, PERIOD_H1, 14, 1);
double sl = NormalizeDouble(Bid - atr * 1.5, _Digits);
这样无论哪个品种、哪个经纪商,止损幅度都跟市场波动挂钩,不会因为合约规格不同而失真。另外,开仓手数也要根据账户杠杆和保证金比例动态计算,别用固定手数。我见过有人用0.1手跑黄金,账户余额2000美元,结果保证金占用过高,浮亏稍微大一点就被强平了。
最后提醒一个新手最容易忽略的环节:MT4的日志文件。很多人EA出问题后直接删掉日志重新跑,其实日志里记录了每一次订单操作、错误代码和服务器响应时间。我排查问题第一件事就是打开「日志」标签页,按时间排序,找 OrderSend error 130(无效止损)或者 invalid price 这类关键词。错误代码130通常意味着你的止损价格没有按照当前报价的Digits精度格式化,比如黄金的报价是小数点后两位,你传了三位进去,就会报错。养成定期检查日志的习惯,比到处问人有用得多。
EA部署不是把代码丢进去就完事。时区、订单隔离、参数扫描、VPS环境、合约规格,每一个细节都可能让策略失效。你如果在部署EA时遇到过类似的诡异问题,留言说说你的踩坑经历,我帮你看看是哪一层出了问题。
免责声明:本文仅代表作者观点,不构成任何投资建议。市场有风险,交易需谨慎。
