MQL5 简介(第 8 部分):初学者构建 EA 交易系统指南(二)(基础篇)
📘

MQL5 简介(第 8 部分):初学者构建 EA 交易系统指南(二)(基础篇)

第 1/3 篇

「EA 到底跑在哪一层」

MQL5 写的自动交易系统(EA)不是独立程序,而是寄生在 MetaTrader 5 客户端里的执行体。你写的策略逻辑编译成 ex5,挂到图表上才生效,行情与下单通道全走 MT5 终端,脱离平台单独跑不了。 这套架构意味着:回测用的是什么点差、什么滑点模型,实盘就可能偏离多少。2025 年 3 月 6 日发布的初学者指南原文里提到,该篇在发布初期就有 1860 次浏览,说明新手对「EA 怎么嵌进终端」这件事的认知缺口很大。 想验证也很直接:开 MT5,Ctrl+N 调出导航器,把任意一个自带 EA 拖到 EURUSD 的 M1 图,立刻能在「专家」标签页看到初始化日志。这一眼就能确认——EA 的生命周期绑定图表周期,换周期不重新加载就不会重算。

◍ 用前一天日K定方向、首根小时K验证的EA思路

学完 MQL5 基础后,真正能落地的第一步是写一个有明确规则的 EA,而不是再啃语法。本篇用基于项目的方式,带你从零搭一个按烛形形态自动决策的机器人,避免论坛里「给了片段却拼不出完整程序」的常见困境。 这个 EA 的逻辑很直接:读前一天的日线烛形——若收阴,当天只找卖点;若收阳,当天只找买点。再用当天第一根 1 小时烛形的收盘价做信号确认,避免裸方向进场。 风控上它很克制:任意时刻只允许 1 个未平仓位,每天最多 2 笔交易;交易时段锁在周一至周三的指定时间,其余时间不盯盘。外汇与贵金属杠杆高、滑点猛,这种硬限制能帮新手压住过度交易的概率。 初学者常卡住的几个点——怎么下买卖单、怎么取 OHLC、怎么不被每个 tick 触发、怎么限单数、怎么设交易时段与星期过滤、怎么给损益封顶——都会在这套代码里逐一现形,你拷过去改几个参数就能在 MT5 策略测试器里跑。

先画逻辑草图再挂交易库

动手写 EA 前,用伪代码把交易逻辑钉死比直接敲代码更省时间。以「前一日收阴则卖、收阳则买」为例,规则要落到具体约束:只在周一至周四跑、单日最多两笔、同时刻仅一个未平头寸、收市平仓。这类清单越具体,后面 MQL5 实现越不容易返工。 MQL5 的库相当于现成的工具书,Trade.mqh 就是管开仓平仓的那一本。你不必重写订单发送细节,只要把它请进项目,再实例化一个 CTrade 对象就能调用。下面这段代码把「引入库—建实例—设幻数」三步一次做完,幻数 103432 用于区分本 EA 与其他来源的下单。 别把正态当圣经:幻数只是标识,不是盈利保证。外汇与贵金属杠杆高、滑点跳空频繁,挂上 CTrade 后仍需在策略测试器里用真实点差回测,确认每日两笔限制真的生效。 代码里 OnInit 中调用 trade.SetExpertMagicNumber(MagicNumber),意味着此后该实例发出的每笔订单都带 103432 标签,便于在终端「交易」标签里筛选自查。

MQL5 / C++
class="macro">#include <Trade/Trade.mqh> class=class="str">"cmt">// Include the trade library for trading functions
class="macro">#include <Trade/Trade.mqh> class=class="str">"cmt">// Include the trade library for trading functions
class=class="str">"cmt">// Create an instance of the CTrade class for trading operations
CTrade trade;
class=class="str">"cmt">//magic number
class="type">int MagicNumber = class="num">103432;
class=class="str">"cmt">//+------------------------------------------------------------------+
class=class="str">"cmt">//| Expert initialization function                                 |
class=class="str">"cmt">//+------------------------------------------------------------------+
class="type">int OnInit()
  {
class=class="str">"cmt">// Set the magic number for the EA&class="macro">#x27;s trades
   trade.SetExpertMagicNumber(MagicNumber);
class=class="str">"cmt">// Return initialization success
   class="kw">return(INIT_SUCCEEDED);
  }
CTrade trade;
class="type">int MagicNumber = class="num">103432;
trade.SetExpertMagicNumber(MagicNumber);

「用 CopyClose 和 CopyOpen 抓取烛形开收价」

判断一根 H1 或 D1 烛形是看涨还是看跌,核心就看收盘价是否高于开盘价。MT5 里不需要自己循环去读缓冲,直接调 CopyClose 与 CopyOpen 就能把指定品种、指定周期的开盘与收盘序列搬进数组。 这两个函数有三种调用形态。第一种按起始位置加数量:start_pos=2、count=5 表示从第 3 根烛形开始连续取 5 根,索引 0 是最旧那根(若未反转序列)。第二种按开始日期加数量:传入 datetime 型的 start_date,如 D'2023.06.01',再给 count=5,就能拿到 6 月 1 日起的 5 根日线收口价。第三种按起止日期:start_date 到 stop_time(如 D'2023.06.05')之间闭区间覆盖的所有烛形被一次性复制。 做日内 EA 时每天手改日期不现实。把 "00:00"、"20:00" 这类字符串用 StringToTime 转成 datetime,它自动绑到当天,无需每日重写。配合 ArraySetAsSeries 把数组设成右到左(最新在索引 0),再用 CopyClose(_Symbol, PERIOD_D1, 2, 5, close_prices) 取最近第 3~7 根日线,就能比价定多空倾向。外汇与贵金属杠杆高,信号仅代表概率倾向,实盘前请在 MT5 策略测试器核对数组索引。

MQL5 / C++
CopyClose(symbol_name, timeframe,  start_pos, count, close_array);
CopyOpen(symbol_name, timeframe,  start_pos, count, open_array);
class="type">class="kw">double close_prices[];
class="type">class="kw">double open_prices[];
CopyClose(_Symbol, PERIOD_D1, class="num">2, class="num">5, close_prices); class=class="str">"cmt">// Copy the close prices of class="num">5 daily candlesticks starting from the 3rd candlestick
CopyOpen(_Symbol, PERIOD_D1, class="num">2, class="num">5, open_prices); class=class="str">"cmt">// Copy the open prices of class="num">5 daily candlesticks starting from the 3rd candlestick
CopyClose(symbol_name, timeframe, timeframe, count, close_array[]);
CopyOpen(symbol_name, timeframe, timeframe, count, open_array[]);
close_prices[];
class="type">class="kw">double open_prices[];
class="type">class="kw">datetime start_date = D&class="macro">#x27;class="num">2023.06.class="num">01 class="num">00:class="num">00&class="macro">#x27;;  class=class="str">"cmt">// Starting from June 1st, class="num">2023
class=class="str">"cmt">// Copy the close prices of class="num">5 daily candlesticks starting from June 1st, class="num">2023
CopyClose(_Symbol, PERIOD_D1, start_date, class="num">5, close_prices);
class=class="str">"cmt">// Copy the open prices of class="num">5 daily candlesticks starting from June 1st, class="num">2023 CopyOpen(_Symbol, PERIOD_D1, start_date, class="num">5, open_prices);
CopyClose( symbol_name, timeframe, start_time, stop_time, close_array[]);
CopyOpen(symbol_name, timeframe, start_time, stop_time, open_array[]);
class="type">class="kw">double close_prices[];
class="type">class="kw">double open_prices[];
class="type">class="kw">datetime start_date = D&class="macro">#x27;class="num">2023.06.class="num">01 class="num">00:class="num">00&class="macro">#x27;; class=class="str">"cmt">// Starting from June 1st, class="num">2023
class="type">class="kw">datetime end_date = D&class="macro">#x27;class="num">2023.06.class="num">05 class="num">00:class="num">00&class="macro">#x27;; class=class="str">"cmt">// Ending on June 5th, class="num">2023
class=class="str">"cmt">// Copy the close prices from June 1st to June 5th
CopyClose(_Symbol, PERIOD_D1, start_date, end_date, close_prices);
class=class="str">"cmt">// Copy the open prices from June 1st to June 5th

常见问题

EA 挂在具体品种图表上,随该图表周期和报价事件触发,不在独立后台进程跑。想验证就开一个图表把 EA 拖上去看日志。
先取昨日日K收线方向作偏向,等今天首根小时K收完且同向再开仓。逻辑草图里写清“日K定调+小时K确认”两步即可。
小布可把你的自然语言策略草图转成模块骨架,标出取价和验证节点,你再补参数就行。
先草图能避开函数堆砌导致的死循环和漏判。草图定好进出条件,再挂 OrderSend 等交易库才不容易乱。
多是索引写反或周期传错。检查是否把第0根当昨收、以及周期参数是否匹配你要的日K或小时K。