简介:这是一份面向零基础读者的MQL自动化交易编程入门文档,围绕MetaTrader 4/5平台上的EA(智能交易程序)编写展开,适合想从零掌握交易策略自动化的外汇、期货及股票交易者与编程初学者。内容从自动化交易概念讲起,系统梳理MQL语言的语法特点、数据类型、变量与常量,并重点介绍交易函数等核心函数库,帮助读者理解如何用MQL编写EA实现自动买卖、图表分析与风险管理。资源包共1个docx文件,约29KB,以图文笔记形式组织,结构清晰,便于按章节顺序阅读与查阅。目前已有1349人学习下载,说明其在入门群体中具有一定参考价值。读者可借此建立MQL编程的基本认知,掌握EA的编写思路与策略实现手段,为后续实盘或模拟环境下的自动化交易实践打下基础。
1. 零基础学 MQL:从 EA 自动化交易编程的门外到能跑通第一单
很多人第一次听到 MQL,是因为手里有一套自己复盘了无数遍的交易规则,却苦于手动盯盘执行不到位。MQL(MetaQuotes Language)是 MetaTrader 平台内置的策略编程语言,分 MQL4 和 MQL5 两代,写出来的程序叫 EA(Expert Advisor,智能交易系统)。它干的事很朴素:把「什么价位、什么条件、下多少手、止损止盈放哪」这套人工动作,翻译成机器能反复执行的代码。零基础能不能学?能,但前提是你别把它当成一门要啃完的通用编程语言,而是当成一套「交易规则的翻译器」。这篇笔记面向三类人:有交易逻辑但不会写代码的、会一点编程但没碰过 MQL 的、以及写过脚本但 EA 一上实盘就翻车的。我会按「先立住概念、再动手复现、最后讲坑」的顺序,把从环境搭建到第一单成交的路径拆开,参数怎么设、失败看哪里,都落到具体操作上。
2. 先把 MQL4 和 MQL5 选明白:别一上来就站错队
2.1 两代语言到底差在哪,选错会多花多少时间
MQL4 和 MQL5 不是简单的版本升级关系,语法相近但运行模型差别很大。MQL4 是面向「单品种、单订单」的老架构,一个货币对一个 EA 实例,订单管理用 OrdersTotal、OrderSelect 这类函数,逻辑直观,新手容易看懂。MQL5 改成了面向「多品种、多持仓」的事件驱动架构,订单和持仓分离,用 PositionSelect、OrderSend 配合 MqlTradeRequest 结构体,功能强但概念多一层。
对零基础的人来说,选型只看一件事:你打算跑在哪个平台、交易什么品种。如果你用的是 MT4 终端,只能写 MQL4;用 MT5 终端,只能写 MQL5,两者不通用。市面上大量教学资料还是 MQL4 的,因为它的语法门槛确实低,一个均线交叉策略几十行就能写完。但如果你未来想做多品种组合、或者平台方只提供 MT5,那就直接上 MQL5,别在 MQL4 上耗时间再迁移。
我一般的建议是:纯新手、只做单品种、目标是「先跑通一单」,从 MQL4 入手;有编程基础、要做组合策略或对接 MT5 的,直接 MQL5。下面这张表是我自己整理的关键差异,选之前对一遍。
| 对比项 | MQL4 | MQL5 |
|---|---|---|
| 运行平台 | MT4 | MT5 |
| 订单模型 | 订单即持仓 | 订单与持仓分离 |
| 多品种支持 | 弱,需多实例 | 原生支持 |
| 回测引擎 | 单线程,精度一般 | 多线程,支持真实 tick |
| 学习曲线 | 平缓 | 偏陡 |
| 适合场景 | 单品种规则化策略 | 组合、高频、复杂风控 |
2.2 环境搭建:从装终端到能编译出第一个 EA
选完语言就动手。以 MQL4 为例,步骤是固定的:装 MT4 终端 → 打开 MetaEditor → 新建 Expert Advisor → 写代码 → 编译 → 挂到图表。这里每一步都有新手会卡的点,我按顺序写清楚。
第一步,装好 MT4 终端后,在终端里按 F4 或者点「工具」菜单里的 MetaEditor,打开代码编辑器。MetaEditor 是随终端一起装的,不用单独下载。
第二步,在 MetaEditor 里点「新建」,选「Expert Advisor(智能交易系统)」,填一个名字,比如 MyFirstEA,一路下一步。它会自动生成一个带 OnInit、OnDeinit、OnTick 三个函数的骨架。这三个函数是 EA 的生命周期入口:OnInit 在 EA 加载时跑一次,OnDeinit 在卸载时跑一次,OnTick 每来一个价格跳动就跑一次。所有交易逻辑基本都写在 OnTick 里。
第三步,先别急着写策略,把骨架编译一遍,确认环境没问题。点「编写」按钮,下方「错误」栏没有红色报错就说明通了。这一步很多人跳过,结果后面报错分不清是环境问题还是代码问题。
第四步,回到 MT4 终端,在「导航器」里找到「智能交易系统」,刷新一下就能看到刚编译的 EA。把它拖到图表上,右上角出现一个笑脸图标,说明 EA 已经加载并在运行。如果出现的是哭脸或者叉,说明自动交易没开,点一下终端上方的「自动交易」按钮。
提示:MT4 默认不允许自动交易,第一次挂 EA 一定要确认「自动交易」按钮是绿色状态,否则 OnTick 根本不会触发,你会以为是代码问题。
2.3 读懂 EA 骨架:三个函数和一次价格跳动
骨架代码长这样,我加了注释:
//+------------------------------------------------------------------+ //| MyFirstEA.mq4 | //+------------------------------------------------------------------+ #property strict // 启用严格模式,新手强烈建议打开 // OnInit:EA 加载时执行一次,用来做初始化 int OnInit() { Print("EA 已加载"); // 在终端「专家」栏输出日志 return(INIT_SUCCEEDED); } // OnDeinit:EA 卸载时执行一次,用来清理资源 void OnDeinit(const int reason) { Print("EA 已卸载,原因代码:", reason); } // OnTick:每来一个 tick 执行一次,交易逻辑写这里 void OnTick() { // 先留空,下一步填逻辑 }逻辑说明:#property strict打开严格模式,会让编译器对类型转换、隐式转换报错,虽然一开始觉得烦,但能帮你避开大量运行时玄学问题。OnInit返回INIT_SUCCEEDED表示初始化成功,如果返回别的值 EA 会直接卸载。OnTick是核心,它的触发频率取决于行情活跃度,活跃时段一秒可能触发多次,冷清时段几分钟才一次,所以任何「每隔多久做一次」的逻辑都不能靠 OnTick 次数来数,要用时间判断。
参数说明:reason是卸载原因代码,常见值 0 表示手动卸载、1 表示程序重编译、2 表示终端关闭,排查 EA 为什么自己停了就看这个日志。
3. 写出第一个能下单的 EA:从均线交叉到订单落地
3.1 策略逻辑先用人话写清楚,再翻译成代码
动手写交易逻辑之前,先用大白话把规则写出来,这一步比写代码重要。我拿一个最经典的均线交叉举例:当快线上穿慢线时买入,下穿时卖出,每次只持一单,带固定止损止盈。用人话描述就是四句话:算快线值、算慢线值、判断有没有持仓、没持仓且发生交叉就下单。
把这四句话对应到 MQL4 的函数:快慢线用 iMA 取,持仓判断用 OrdersTotal,下单用 OrderSend。这里有个新手最容易翻车的点:iMA 取的是指标句柄还是指标值,MQL4 和 MQL5 完全不一样。MQL4 里 iMA 直接返回值,MQL5 里 iMA 返回句柄、要用 CopyBuffer 取值。下面代码是 MQL4 版本。
3.2 完整可编译代码:均线交叉下单 EA
#property strict // ---- 可调参数 ---- input int FastPeriod = 5; // 快线周期 input int SlowPeriod = 20; // 慢线周期 input double LotSize = 0.01; // 下单手数 input int StopLoss = 300; // 止损,单位点 input int TakeProfit = 600; // 止盈,单位点 input int MagicNum = 20240101; // 魔术号,区分本 EA 的订单 // OnTick:每 tick 检查一次交叉信号 void OnTick() { // 1. 只在新 K 线开盘时判断,避免同一根 K 线反复下单 static datetime lastBarTime = 0; datetime curBarTime = iTime(Symbol(), PERIOD_CURRENT, 0); if(curBarTime == lastBarTime) return; lastBarTime = curBarTime; // 2. 已有持仓就不再开新单 if(CountMyOrders() > 0) return; // 3. 取前两根 K 线的快慢线值,判断交叉 double fastNow = iMA(Symbol(), PERIOD_CURRENT, FastPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double fastPrev = iMA(Symbol(), PERIOD_CURRENT, FastPeriod, 0, MODE_SMA, PRICE_CLOSE, 2); double slowNow = iMA(Symbol(), PERIOD_CURRENT, SlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 1); double slowPrev = iMA(Symbol(), PERIOD_CURRENT, SlowPeriod, 0, MODE_SMA, PRICE_CLOSE, 2); bool crossUp = (fastPrev <= slowPrev) && (fastNow > slowNow); bool crossDown = (fastPrev >= slowPrev) && (fastNow < slowNow); // 4. 根据交叉方向下单 if(crossUp) OpenOrder(OP_BUY); if(crossDown) OpenOrder(OP_SELL); } // 统计本 EA 的持仓数量,用魔术号过滤 int CountMyOrders() { int cnt = 0; for(int i = 0; i < OrdersTotal(); i++) { if(!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue; if(OrderMagicNumber() == MagicNum && OrderSymbol() == Symbol()) cnt++; } return cnt; } // 下单函数:根据方向计算止损止盈价并发送订单 void OpenOrder(int type) { double price = (type == OP_BUY) ? Ask : Bid; double sl = 0, tp = 0; double point = Point; if(type == OP_BUY) { sl = price - StopLoss * point; tp = price + TakeProfit * point; } else { sl = price + StopLoss * point; tp = price - TakeProfit * point; } int ticket = OrderSend(Symbol(), type, LotSize, price, 3, sl, tp, "MyFirstEA", MagicNum, 0, clrGreen); if(ticket < 0) Print("下单失败,错误码:", GetLastError()); else Print("下单成功,订单号:", ticket); }逻辑说明:OnTick里第一件事是用lastBarTime做新 K 线判断,这是防止同一根 K 线反复触发信号的关键,很多新手 EA 一挂上去就疯狂下单,八成是漏了这一步。第二步用魔术号统计持仓,保证同一时间只有一单。第三步取第 1、2 根 K 线的均线值判断交叉,注意索引 1 是上一根已收盘 K 线,索引 0 是当前未收盘 K 线,用 0 会导致信号闪烁。第四步调用下单函数。
参数说明:FastPeriod、SlowPeriod是均线周期,改这两个值等于换策略;LotSize是手数,实盘前务必用最小手数验证;StopLoss、TakeProfit单位是「点」,不是价格,MT4 里 1 点通常等于 0.0001(五位数报价),黄金、指数品种的 point 值不同,要单独确认;MagicNum是魔术号,同一账户跑多个 EA 时必须各不相同,否则订单会互相干扰。
3.3 编译、挂载、看日志:确认第一单真的成交
代码写完点「编写」,错误栏为空后回到 MT4。把 EA 拖到图表上,弹窗里确认参数,点确定。然后打开终端下方的「专家」标签,看有没有输出「EA 已加载」。等行情走到交叉条件,日志里会出现「下单成功,订单号:xxx」,同时「交易」标签里能看到持仓。
如果日志里出现「下单失败,错误码:xxx」,把错误码对照一下:130 是止损止盈设置非法,通常是方向算反了或者距离太近;131 是手数不合法,检查最小手数;134 是保证金不足;138 是报价刷新太快,重发即可。这几个是新手最常撞的。
注意:第一次测试一定用模拟账户,别拿实盘试。模拟账户的成交逻辑和实盘有差异,但足以验证代码逻辑对不对。
4. 回测和参数调优:别让 EA 只在历史里赚钱
4.1 用策略测试器跑一遍,先看它是不是过拟合
EA 能下单不代表策略有效。MT4 自带策略测试器,在终端按 Ctrl+R 打开。选好 EA、品种、周期、时间范围,模型选「每 tick」,点「开始」。跑完后重点看三个数:总净利润、最大回撤、交易次数。交易次数太少(比如几十次)的测试结果没有统计意义,几百次以上才值得看。
这里有个血泪经验:很多人调参数调到历史曲线完美,一上实盘就亏。原因是过拟合——参数只适配了那段历史行情。判断方法很简单,把历史区间分成两段,前一段调参,后一段验证,如果后一段表现明显变差,就是过拟合了。我一般会把快慢线周期、止损止盈做成参数组,跑优化后不直接选利润最高的,而是选参数附近一片区域表现都稳定的那组,这叫「参数平原」,比单点最优靠谱。
4.2 三个必调参数和它们的合理范围
回测里真正影响结果的参数没几个,别贪多。以均线交叉为例,核心就三个:快线周期、慢线周期、止损止盈比。
快线周期一般取 3 到 10,太小会被噪音带着频繁交易,太大就失去「快」的意义。慢线周期取 15 到 50,快慢比保持在 1:3 到 1:5 之间比较常见。止损止盈比要看策略的胜率,胜率高的策略可以止盈小于止损,胜率低的必须让盈亏比大于 1,否则长期必亏。这三个参数不要一起优化,先固定两个调一个,否则组合爆炸,跑一晚上也跑不完,还容易过拟合。
| 参数 | 常见范围 | 调大后果 | 调小后果 |
|---|---|---|---|
| 快线周期 | 3–10 | 信号变少、滞后 | 噪音交易增多 |
| 慢线周期 | 15–50 | 趋势确认慢 | 假信号增多 |
| 盈亏比 | 0.5–3 | 胜率要求高 | 单笔亏损大 |
4.3 从回测到模拟盘的过渡检查清单
回测好看之后,别直接上实盘,先挂模拟盘跑一到两周。这一步是验证「代码在真实报价环境下会不会出问题」,重点检查四件事:订单有没有重复发送、止损止盈有没有正确挂上、EA 在终端重启后能不能恢复状态、日志里有没有异常错误码。这四件事回测里不一定暴露,但实盘环境一定会遇到。
模拟盘跑通后,实盘第一周用最小手数,把「代码逻辑正确」和「策略赚钱」分开验证。代码逻辑正确看日志和订单,策略赚不赚钱看长期统计,别混在一起判断。
5. 避坑与排查:EA 上实盘前必须过的五道坎
5.1 现象:EA 挂上去一单都不下
原因通常有三个:自动交易按钮没开、OnTick 里被新 K 线判断卡住、或者信号条件永远不成立。排查顺序是先看终端右上角笑脸在不在,再看「专家」日志有没有输出,最后在 OnTick 里加一行 Print 把快慢线值打出来,看条件到底差多少。我遇到过最隐蔽的一次是品种的 point 值和预期不一样,止损算出来是负数,OrderSend 直接返回错误,但日志没细看就以为是信号问题。
5.2 现象:同一根 K 线反复下单
原因就是漏了新 K 线判断,或者判断写在了错误的位置。解决方法是像 3.2 的代码那样,用iTime(Symbol(), PERIOD_CURRENT, 0)记录当前 K 线时间,和上一次比较,相同就直接 return。注意这个 static 变量在 EA 重新加载后会重置,所以重编译后第一根 K 线可能重复触发一次,属于正常现象。
5.3 现象:回测赚钱实盘亏钱
原因分两类:过拟合和执行差异。过拟合靠分段验证排查,执行差异靠对比回测和实盘的成交价、滑点、点差。回测里点差是固定的,实盘点差会扩大,尤其新闻时段。解决办法是在回测里把点差设成实盘的平均值甚至偏大值,如果这样还能盈利,实盘才有戏。
5.4 现象:订单止损止盈挂不上
原因是止损止盈价距离当前价太近,触发了平台的最小止损距离限制,错误码 130。解决方法是下单前用MarketInfo(Symbol(), MODE_STOPLEVEL)取平台要求的最小距离,算出来的止损止盈价如果太近就调整或者放弃这笔。不同平台这个值不一样,代码里写死数字迟早翻车。
5.5 现象:EA 跑几天后自己停了
原因可能是终端重启、网络断开、或者 EA 内部某个数组越界导致崩溃。排查看「专家」日志的最后几行,通常有线索。预防办法是在 OnInit 里做参数合法性检查,比如周期不能为负、手数不能小于最小手数,不合法就返回 INIT_PARAMETERS_INCORRECT 让 EA 拒绝加载,而不是带着错误参数跑。
6. 进阶一点:把 EA 从「能跑」做到「敢用」
写到能下单只是起点,真正决定 EA 能不能长期用的是工程细节。我自己的习惯是给每个 EA 加三层保护:资金层、执行层、监控层。
资金层是仓位管理。固定手数只适合验证阶段,实盘要按账户净值的百分比算手数,比如每笔风险不超过净值的 1%。算法是:手数 = 净值 × 风险比例 ÷(止损点数 × 每点价值)。每点价值用MarketInfo(Symbol(), MODE_TICKVALUE)取,不同品种差别很大,不能写死。
执行层是订单容错。OrderSend 返回失败不能直接放弃,要区分可重试和不可重试的错误。报价刷新(138)、服务器忙(136)这类可以等几十毫秒重发,参数错误(130、131)重发多少次都没用。我一般写一个带重试次数的下单封装,最多重试三次,每次间隔用 Sleep 控制。
监控层是状态自检。EA 每隔一段时间检查一次:持仓数量是否符合预期、止损止盈是否还在、账户可用保证金是否充足。发现异常就写日志并停止开新仓,而不是继续闷头跑。这一步很多人省掉,结果某天发现止损被手动改过、EA 还在按原逻辑加仓,亏损放大。
验证方法上,除了回测和模拟盘,我还会做一次「断网测试」:模拟盘跑着的时候把网络断开几分钟再恢复,看 EA 能不能正确恢复状态、有没有重复下单。这个测试能暴露很多状态管理的问题,比单纯看回测曲线有用得多。
最后说个我自己的教训:早期我写 EA 总想一次把所有功能加进去,结果一个 bug 要找半天。后来改成每次只加一个功能,加完就在模拟盘跑一天,确认没问题再加下一个。慢是慢了点,但省下的排查时间远超这点等待。EA 这东西,能跑不等于敢用,敢用靠的是一层层验证堆出来的信心。希望帮到你。
本文还有配套的精品资源,点击获取