Table of Contents
MetaTrader 5 与 Python:官方包还是本地 Socket 桥接?
将 MetaTrader 5 连接到 Python,实用的方法主要有两种:
- 使用 MetaQuotes 官方
MetaTrader5Python 包,与本机的 MetaTrader 5 终端通信。 - 让 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(),但检查成功并不保证交易能够执行。执行规则、成交方式、交易品种名称、市场时间、交易量步长、账户权限和返回码,都会因终端、经纪商、账户和品种而异。
按以下顺序搭建连接:
- 确认 Python 包和终端版本。
- 读取终端信息和交易品种信息。
- 获取少量 K 线并检查时间戳。
- 记录错误,但不要把凭据或不必要的账户标识写入日志。
- 完成上述步骤后,才在模拟账户中测试经过明确审阅的订单请求。
对于任何下单路径,都要同时检查 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 日。
