MetaTrader 5 与 Python:官方包还是本地 Socket 桥接?

MetaTrader 5 与 Python:官方包还是本地 Socket 桥接?

将 MetaTrader 5 连接到 Python,实用的方法主要有两种:

  1. 使用 MetaQuotes 官方 MetaTrader5 Python 包,与本机的 MetaTrader 5 终端通信。
  2. 让 MQL5 Expert Advisor 或脚本通过 Socket 与 Python 服务交换消息。

如果 Python 需要读取终端状态、账户信息、交易品种、tick 或 K 线,官方包的路径更短。如果希望由 Expert Advisor 保留控制权,而 Python 只提供计算或模型结果,则 Socket 桥接更合适。

下文示例只读取终端信息,或返回不执行操作的 Socket 响应,不会下单。任何自动化都应先在模拟账户中测试,并把通信失败视为不执行操作的理由。

MetaTrader5 包目前的平台限制

截至 2026 年 9 月 9 日,PyPI 上的 `MetaTrader5` 最新版本是 5.0.6180,只提供适用于 Windows x86-64 的 CPython wheel,没有源码分发包。因此,实际使用时应在 64 位 Windows 上安装此包并运行 MetaTrader 5 终端。在 Linux 或 macOS 上执行普通的 pip install MetaTrader5,目前没有匹配的官方包文件。

MetaQuotes 将此包描述为与 MetaTrader 5 终端的进程间连接。它不是独立于经纪商的市场数据 API。脚本看到的交易品种、历史数据、账户状态和权限,都来自所连接的终端及其当前配置的交易账户。

建议安装到虚拟环境,不要直接装进系统 Python:

py -m venv .venv
..venvScriptspython.exe -m pip install --upgrade pip
..venvScriptspython.exe -m pip install MetaTrader5

如果 pip 提示找不到匹配的分发包,请检查 Python 是否为 64 位 CPython,并确认当前 Python 版本在 PyPI 文件列表中有对应 wheel。

不在代码中写入凭据也能连接终端

最简单的连接方式,是使用终端当前已选择的账户:

import MetaTrader5 as mt5

if not mt5.initialize():
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    print("Python package:", mt5.__version__)
    print("Terminal version:", mt5.version())
finally:
    mt5.shutdown()

根据 `initialize()` 文档,必要时该调用可以启动终端。如果电脑中安装了多个 MetaTrader,应明确指定要连接的终端程序:

import MetaTrader5 as mt5

terminal = r"C:Program FilesMetaTrader 5terminal64.exe"

if not mt5.initialize(terminal, timeout=60_000):
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    print(mt5.version())
finally:
    mt5.shutdown()

不要把账户密码写入源码、Notebook、截图或日志。如果脚本只需要使用终端已保存的会话,就不必传入登录凭据。

安全读取近期 K 线

下面的示例会在 Market Watch 中选择交易品种、请求 K 线、处理空结果,并确保最终关闭包连接:

from datetime import datetime, timezone

import MetaTrader5 as mt5

symbol = "EURUSD"
timeframe = mt5.TIMEFRAME_M1
start_position = 1  # skip the current, still-forming bar
count = 100

if not mt5.initialize():
    raise RuntimeError(f"initialize() failed: {mt5.last_error()}")

try:
    if not mt5.symbol_select(symbol, True):
        raise RuntimeError(
            f"symbol_select({symbol!r}) failed: {mt5.last_error()}"
        )

    rates = mt5.copy_rates_from_pos(
        symbol,
        timeframe,
        start_position,
        count,
    )

    if rates is None or len(rates) == 0:
        raise RuntimeError(f"no bars returned: {mt5.last_error()}")

    for row in rates[:5]:
        opened = datetime.fromtimestamp(int(row["time"]), tz=timezone.utc)
        print(opened.isoformat(), row["open"], row["high"], row["low"], row["close"])
finally:
    mt5.shutdown()

不同经纪商的交易品种名称可能不同,例如 EURUSD.a,因此不要假定名称固定,应在终端中确认。在 `copy_rates_from_pos()` 中,位置 0 是仍在形成的当前 K 线;如果计算只应使用已收盘 K 线,请从位置 1 开始。可读取的历史数据量还受终端 Max. bars in chart 设置限制。MetaQuotes 在 `copy_rates_from()` 注意事项中说明 K 线和 tick 时间使用 UTC,因此 Python 中也应使用带时区的 UTC 时间。

第一次测试不要发送订单

该包提供 order_check()order_send(),但检查成功并不保证交易能够执行。执行规则、成交方式、交易品种名称、市场时间、交易量步长、账户权限和返回码,都会因终端、经纪商、账户和品种而异。

按以下顺序搭建连接:

  1. 确认 Python 包和终端版本。
  2. 读取终端信息和交易品种信息。
  3. 获取少量 K 线并检查时间戳。
  4. 记录错误,但不要把凭据或不必要的账户标识写入日志。
  5. 完成上述步骤后,才在模拟账户中测试经过明确审阅的订单请求。

对于任何下单路径,都要同时检查 last_error() 和返回的交易结果。应把 `order_check()` 视为一道验证步骤,而不是执行承诺;请求与结果结构请参阅 `order_send()` 文档

何时更适合使用 Socket 桥接

Socket 桥接让接触 MetaTrader 的循环保留在 MQL5 内部,而 Python 作为独立服务工作。以下情况适合这种结构:

  • 现有 Expert Advisor 已经管理时序和订单状态;
  • Python 负责 MQL5 中不便实现的计算;
  • 消息需要自定义结构或版本化协议;
  • Python 不可用时,MQL5 端仍必须安全运行。

MetaTrader 的网络函数文档要求用户在 Tools > Options > Expert Advisors 中手动加入目标地址。Socket 函数只能由 Expert Advisor 和脚本调用,不能在指标中调用。`SocketConnect()` 必须传入有限的连接超时;还应使用 `SocketTimeouts()` 设置收发超时,因为默认的零值可能无限等待。

同一台电脑上的桥接服务,应让 Python 绑定到 127.0.0.1,而不是 0.0.0.0。普通 TCP 不会认证或加密消息。如果 Python 服务必须运行在另一台机器上,应使用带身份验证和 TLS 的受保护网络设计,不要暴露未经认证的交易控制端口。

下面是一个刻意保持简单、每次只处理一个请求的消息边界测试服务器:

import json
import socket

HOST = "127.0.0.1"
PORT = 9090
MAX_MESSAGE = 64 * 1024

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as server:
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind((HOST, PORT))
    server.listen(5)
    print(f"Listening on {HOST}:{PORT}")

    while True:
        conn, address = server.accept()
        with conn:
            conn.settimeout(5)
            with conn.makefile("rwb") as stream:
                try:
                    line = stream.readline(MAX_MESSAGE + 1)
                except OSError:
                    continue

                if not line or len(line) > MAX_MESSAGE or not line.endswith(b"n"):
                    reply = {"status": "error", "action": "none"}
                else:
                    try:
                        request = json.loads(line.decode("utf-8"))
                        if not isinstance(request, dict):
                            raise ValueError("request must be a JSON object")
                        request_id = request.get("request_id")
                        if (
                            not isinstance(request_id, str)
                            or not request_id.strip()
                            or len(request_id) > 128
                        ):
                            raise ValueError("invalid request_id")
                        reply = {
                            "status": "ok",
                            "request_id": request_id,
                            "action": "none",
                        }
                    except (UnicodeDecodeError, json.JSONDecodeError, ValueError):
                        reply = {"status": "error", "action": "none"}

                try:
                    stream.write(json.dumps(reply).encode("utf-8") + b"n")
                    stream.flush()
                except OSError:
                    continue

这只是消息分帧示例,不是生产级交易服务。实际协议应包括版本号、请求 ID、时间戳、严格的字段验证、消息大小限制和幂等规则。MQL5 端应使用 `SocketConnect()``SocketTimeouts()`,拒绝过期或格式错误的响应,并在超时或断线后默认不执行操作。

应该选择哪一种?

如果 Python 运行在受支持的 Windows 上,MetaTrader 终端位于本机,而且 Python 需要直接读取终端数据或账户状态,请使用官方包。

如果希望 Expert Advisor 保留控制权、Python 只是边界清晰的计算服务,或自定义消息协议比官方包的便利性更重要,请使用 Socket 桥接。

无论选择哪种方式,都应从只读操作开始,记录准确的包版本和终端版本,使用经纪商实际提供的品种名称测试,不在代码中保存凭据,并确保通信失败的结果是“不交易”,而不是临时猜测一个替代动作。

如果想了解实际项目中的用法,而不是直接复制模板,可查看 MicroQuant 的 MT5 客户端。它演示的是通过官方包初始化终端并获取 OHLC K 线,而不是 Socket 桥接。该文件也包含真实下单路径,因此请先仔细审查,并仅在模拟账户中测试。

一手资料

核对日期:2026 年 9 月 9 日。

Leave a Reply