**运行环境**: Windows VPS(MT5 终端 + Python 3.11+)
**架构**: 纯 Python(零 EA),MetaTrader5 库直连 MT5 终端
1. 持仓检查,全/半自动化交易,账户监控,全自动日报月报等功能
(对接AI助手后) 。
2. 配合EA邦EA交易,目前已经实测。比如,对
Hedging对冲EA的订单进行日报,分品种汇报,持仓优化建议,干预EA订单
(对接AI助手后) 。
3. 通过QQ/微信/TG等各种工具,直接自然语言操盘,比如:本日/月盈亏,下单0.01手欧美,平仓0.01手黄金,对最早的黄金订单平仓等
(对接AI助手后) 。
4. 使用各种自动化脚本控制远程服务器上的MT5交易客户端。
5. 可本地/远程,如果不希望运行在远程服务器上,也可以做少量修改,去掉远程部分,既可对接各类工具(包括AI助手)。
3. [MT5 终端配置要求](#3-mt5-终端配置要求)
4. [Python 服务端设计](#4-python-服务端设计)
5. [REST API 接口定义](#5-rest-api-接口定义)
6. [WebSocket 协议](#6-websocket-协议)
10. [附录:技术选型说明](#10-附录技术选型说明)
┌──────────────────── Windows VPS ────────────────────────┐
│ ┌──────────────────┐ ┌───────────────────────────┐ │
│ │ MT5 终端 │ │ Python 控制服务 │ │
│ │ • 已登录交易账号 │◄───│ • MetaTrader5 (IPC) │ │
│ │ • 终端保持运行 │ │ • FastAPI (REST API) │ │
│ │ • 自动重启配置 │ │ • WebSockets (实时推送) │ │
│ └──────────────────┘ │ • asyncio (异步IO) │ │
│ └────────┬──────────────────┘ │
│ HTTPS :8080 / WSS :8081 │
└────────────────────────────┬───────┴──────────────────────┘
|:----|:----|:----|:----|
| **控制** | REST (HTTPS) | 下单、改单、撤单、查询 | 远程 → VPS |
| **查询** | REST (HTTPS) | 账户/持仓/行情/K线/指标 | 远程 → VPS |
| **推送** | WebSocket (WSS) | 实时报价、成交推送、P&L变化 | VPS → 远程 |
| Python | CPython | 3.11+ |
| MT5 接口 | MetaTrader5 (pip) | ≥5.0.45 |
| Web 框架 | FastAPI | ≥0.110 |
| 异步 | uvicorn + asyncio | — |
| WebSocket | websockets (FastAPI built-in) | — |
| 安全 | pyjwt + passlib[bcrypt] | — |
├── main.py # 服务入口(FastAPI app + 启动逻辑)
├── config.yaml # 配置文件(端口、Token、白名单等)
├── requirements.txt # Python 依赖
│ ├── mt5_client.py # MetaTrader5 封装(连接/重连/交易/查询)
│ ├── command_queue.py # 命令队列(异步任务编排)
│ ├── heartbeat.py # MT5 终端心跳检测 + 自动重连
│ └── event_bus.py # 事件总线(报价/成交/持仓变化通知)
│ ├── routes_account.py # /api/v1/account/* (账户信息)
│ ├── routes_trade.py # /api/v1/order/* (交易操作)
│ ├── routes_market.py # /api/v1/symbol/*, /api/v1/rates/* (市场数据)
│ └── ws_handler.py # WebSocket 连接管理
│ ├── auth.py # Token 生成/验证
│ ├── ip_whitelist.py # IP 白名单检查
│ └── rate_limiter.py # API 频率限制
│ ├── order.py # 订单数据模型(pydantic)
│ ├── account.py # 账户数据模型
│ ├── install_service.bat # 安装为 Windows 服务
│ ├── restart_mt5.bat # 重启 MT5 终端脚本
| 操作系统 | Windows Server 2016/2019/2022 或 Windows 10/11 |
| MT5 版本 | 最新 Build(≥4000) |
| 自动交易 | **启用**(工具 → 选项 → EA交易 → 允许自动交易) |
| DDE | 无需额外配置(mt5python 使用内置 IPC) |
**Windows 任务计划程序** — MT5 崩溃后自动重启:
操作: 启动 "C:\Program Files\MetaTrader 5\terminal64.exe"
- 工具 → 选项 → EA 交易 → 勾选「当系统重启时自动启动 EA」
**监控脚本** (`scripts/restart_mt5.bat`):
tasklist /FI "IMAGENAME eq terminal64.exe" 2>NUL | find /I /N "terminal64.exe" >NUL
start "" "C:\Program Files\MetaTrader 5\terminal64.exe"
echo %date% %time% MT5 restarted >> C:\MT5Controller\logs\mt5_monitor.log
#### 4.1.1 `core/mt5_client.py` — MT5 连接封装
async def initialize(self) -> bool # 连接 MT5 终端
async def shutdown(self) # 断开连接
async def is_connected(self) -> bool # 检查连接状态
async def order_send(self, request: TradeRequest) -> TradeResult
async def order_modify(self, ticket: int, **params) -> bool
async def order_close(self, ticket: int) -> bool
async def close_all(self, symbol: str = None) -> List[TradeResult]
async def get_account_info(self) -> AccountInfo
async def get_positions(self, symbol: str = None) -> List[Position]
async def get_orders(self, symbol: str = None) -> List[Order]
async def get_history(self, from_date: datetime, to_date: datetime) -> List[Deal]
async def get_symbol_info(self, symbol: str) -> SymbolInfo
async def get_tick(self, symbol: str) -> Tick
async def get_rates(self, symbol: str, tf: int, count: int) -> List[Rate]
async def get_rates_range(self, symbol: str, tf: int,
from_dt: datetime, to_dt: datetime) -> List[Rate]
async def get_indicator(self, symbol: str, tf: int,
name: str, **params) -> List[float]
└─ 指数退避(5s → 10s → 20s → 30s → 上限60s)
└─ 仍失败 → 记录日志,返回错误,等待下一次心跳检查
#### 4.1.2 `core/event_bus.py` — 事件总线
async def subscribe_ticks(self, symbols: List[str], ws_client_id: str)
async def unsubscribe_ticks(self, ws_client_id: str)
async def broadcast_account_update(self, account: AccountInfo)
async def broadcast_trade_result(self, result: TradeResult)
#### 4.1.3 `core/heartbeat.py` — 终端保活
每收到一个新的 Tick(约 100-500ms 间隔),
通过 WebSocket 推送给所有订阅了该品种的客户端。
3. 初始化 MT5Client(连接 MT5 终端)
6. 启动 FastAPI(uvicorn :8080)
全程如果 MT5 初始化失败 → 写入日志,HTTP API 返回 503
| 认证方式 | `Authorization: Bearer <token>` |
| 请求体 | JSON (`application/json`) |
| 响应格式 | `{"success": true, "data": {...}}` 或 `{"success": false, "error": "..."}` |
| HTTP 状态码 | 200=成功, 400=参数错误, 401=认证失败, 403=IP拒绝, 404=不存在, 429=限流, 500=服务端错误, 503=MT5未连接 |
#### `GET /api/v1/account`
"server": "ICMarkets-Demo",
"server_time": "2026-05-05T12:30:00",
"connected_since": "2026-05-05T08:00:00"
#### `GET /api/v1/positions`
#### `GET /api/v1/positions?symbol=EURUSD`
"current_price": 1.08750,
"open_time": "2026-05-04T14:30:00",
#### `GET /api/v1/orders/pending`
#### `POST /api/v1/order/open`
|:----|:----|:----|:-----|
| symbol | string | ✅ | 品种名,如 "EURUSD" |
| type | string | ✅ | "buy" / "sell" / "buy_limit" / "sell_limit" / "buy_stop" / "sell_stop" |
| volume | float | ✅ | 手数,最小0.01,步进0.01 |
| price | float | ❌ | 市价单填0或省略;挂单填触发价 |
| sl | float | ❌ | 止损价,0=不设 |
| tp | float | ❌ | 止盈价,0=不设 |
| comment | string | ❌ | 订单备注,最多32字符 |
| magic | int | ❌ | EA标识号,默认0 |
| deviation | int | ❌ | 允许滑点(点数),默认10 |
"open_time": "2026-05-05T12:30:05.123",
#### `POST /api/v1/order/modify`
|:----|:----|:----|:-----|
| ticket | int | ✅ | 订单号 |
| sl | float | ❌ | 新止损,不传则不修改 |
| tp | float | ❌ | 新止盈,不传则不修改 |
#### `POST /api/v1/order/close`
#### `POST /api/v1/order/close_all`
#### `GET /api/v1/symbol/{name}`
"time": "2026-05-05T12:30:01.000",
"margin_currency": "EUR",
"trade_calc_mode": "forex"
#### `GET /api/v1/symbols`
#### `GET /api/v1/rates/{symbol}?tf=h1&count=100`
| 参数 | 类型 | 必填 | 默认 | 说明 |
|:----|:----|:----|:----|:-----|
| tf | string | ❌ | "h1" | 时间周期: m1,m5,m15,m30,h1,h4,d1,w1,mn |
| count | int | ❌ | 100 | K线数量,最大1000 |
#### `GET /api/v1/rates/{symbol}/range?tf=h1&from=2026-05-01T00:00:00&to=2026-05-05T00:00:00`
"time": "2026-05-05T12:00:00",
#### `GET /api/v1/indicators/{symbol}?tf=h1&name=MA&period=10&shift=0&ma_method=sma&applied_price=close&count=100`
| 参数 | 类型 | 必填 | 默认 | 说明 |
|:----|:----|:----|:----|:-----|
| tf | string | ❌ | "h1" | 时间周期 |
| name | string | ✅ | — | 指标名: MA, EMA, RSI, MACD, BollingerBands, Stochastic, Ichimoku 等 |
| count | int | ❌ | 100 | K线数量 |
| *指标特有参数 | — | ❌ | — | 如 MA: period, ma_method, applied_price |
"params": {"period": 10, "method": "sma", "applied_price": "close"},
"values": [1.08650, 1.08655, 1.08660, ...]
#### `GET /api/v1/health`
"active_ws_connections": 3,
ws://<VPS_IP>:8081/api/v1/ws?token=<bearer_token>
{"action": "subscribe", "channel": "ticks", "symbols": ["EURUSD", "XAUUSD", "GBPUSD"]}
{"action": "unsubscribe", "channel": "ticks", "symbols": ["EURUSD"]}
{"action": "subscribe", "channel": "account"}
{"action": "subscribe", "channel": "trades"}
"time": "2026-05-05T12:30:01.500"
"time": "2026-05-05T12:30:05.123"
客户端应回复 `{"action": "pong"}`,否则 60 秒后断开。
|:----|:-----|:---------|
| **传输层** | HTTPS (TLS 1.3) + 自签名证书 | uvicorn / nginx反向代理 |
| **认证层** | Bearer JWT Token,过期时间可配 | FastAPI middleware |
| **访问层** | IP 白名单,可配置多个 CIDR | FastAPI middleware |
token: "mt5-ctrl-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" # 静态 Token(推荐)
jwt_secret: "your-256-bit-secret-here"
jwt_expire_minutes: 1440 # 24小时
Authorization: Bearer mt5-ctrl-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
- 静态 Token 方式:重启服务时更新 `config.yaml` 的 Token,通过 RDP 或远程管理工具安全修改
- JWT 方式:增加 `/api/v1/auth/login` 获取新 Token(需主 Token 认证)
- "203.0.113.0/24" # 授权的远程 IP 段
- "your.home.ip.addr/32" # 具体的家庭/办公 IP
**注意:** 白名单只对 REST API 生效。WebSocket 连接同样需要 Token 认证。
max_order_volume: 10.0 # 单笔最大手数
max_total_positions: 50 # 最大持仓数
max_daily_loss: 1000.0 # 每日最大亏损(0=不限制)
allowed_symbols: # 空=所有品种
read_only_mode: false # 只读模式(仅查询,禁止交易)
requests_per_minute: 60 # 每分钟最大请求数
1. Windows VPS 购买 & RDP 连接
├─ 推荐配置:2C4G, 40GB SSD, Windows Server 2019+
└─ 开放端口:8080(TCP), 8081(TCP) 在防火墙中
├─ 工具 → 选项 → EA 交易 → 勾选「允许自动交易」
├─ 下载 python-3.11.x-amd64.exe
├─ 安装时勾选「Add Python to PATH」
└─ 打开 CMD 验证: python --version
pip install -r requirements.txt
uvicorn[standard]==0.27.0
file: "logs/mt5_controller.log"
path: "C:\\Program Files\\MetaTrader 5\\terminal64.exe"
reconnect_interval_sec: 5
max_reconnect_attempts: 10
heartbeat_interval_sec: 10
token: "mt5-ctrl-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
**注册为 Windows 服务(开机自启):**
scripts\install_service.bat
**install_service.bat 内容:**
sc create "MT5Controller" binPath="cmd /c C:\Python311\python.exe C:\MT5Controller\main.py" start=auto
sc description "MT5Controller" "MT5 Remote Control Service"
echo Service installed and started.
curl http://127.0.0.1:8080/api/v1/health
curl -H "Authorization: Bearer mt5-ctrl-xxxxxxxx" https://<VPS_IP>:8080/api/v1/account
日志文件位于 `C:\MT5Controller\logs\mt5_controller.log`。
日志轮转策略:每个文件 10MB,保留 30 天。
2026-05-05 12:30:00.123 | INFO | mt5_client:initialize:42 - MT5 initialized, server: ICMarkets-Demo
2026-05-05 12:30:00.456 | INFO | server:startup:18 - HTTP server started on :8080
2026-05-05 12:30:01.000 | DEBUG | mt5_client:get_tick:156 - EURUSD tick: bid=1.08725 ask=1.08728
2026-05-05 12:30:05.000 | INFO | routes_trade:open:34 - Order opened: ticket=100001 EURUSD buy 0.10 @1.08650
2026-05-05 12:30:05.001 | INFO | ws_handler:broadcast:89 - Trade broadcast sent to 1 client(s)
|:----|:---------|:---------|
| `/api/v1/health` 返回 `mt5_connected: false` | MT5 终端未启动或未登录 | 检查 MT5 是否运行并登录 |
| 报错 `no module named 'MetaTrader5'` | 未安装依赖 | 运行 `pip install MetaTrader5` |
| 远程连接被拒绝 | 防火墙未开放端口 | Windows 防火墙添加入站规则: 8080, 8081 |
| Token 验证失败 | Token 不匹配 | 检查 `config.yaml` 中的 `security.token` |
| 下单返回 `error_code: 10018` | 交易时间外 | 检查经纪商交易时间 |
| WebSocket 频繁断开 | 网络不稳定 | 调整客户端重连间隔,服务端检查 `ping_interval` |
1. 备份配置:copy C:\MT5Controller\config.yaml config_backup.yaml
2. 备份日志:copy C:\MT5Controller\logs logs_backup\
3. 停止服务:sc stop "MT5Controller"
5. 启动服务:sc start "MT5Controller"
- 任务管理器结束 `terminal64.exe`
- `scripts\restart_mt5.bat` 自动重启
- Windows 服务自动重启策略(`sc failure "MT5Controller" reset=86400 actions=restart/5000`)
- MT5 + Python 服务均已设为开机自启
- 启动顺序:MT5 终端(自动登录)→ Python 服务(自动连接)
| 对比项 | EA + Bridge | 纯 Python |
|:----|:-----------|:----------|
| 开发语言 | MQL5 + Python | **Python 单语言** |
| 编译部署 | EA 需编译 `.ex5` 放入 MT5 目录 | **无需编译,直接运行** |
| 调试 | MQL5 调试器弱,打印日志麻烦 | **Python 生态完善(pdb/IDE)** |
| 功能上限 | MQL5 标准库有限 | **Python 全生态(pandas/TA-Lib/ML)** |
| 延迟 | TCP 轮询 ~200ms | **IPC 直连 < 50ms** |
| 维护成本 | 双端代码同步 | **单端维护** |
### 10.2 为什么不直接使用 mt5python 从远程调用?
因为 mt5python 的 `initialize()` 要求 Python 进程与 MT5 终端在同一台机器上(通过 Windows IPC)。远程调用必须依赖一个本地代理服务(即本方案的 FastAPI)。
### 10.3 为什么不使用 nginx 反向代理?
- FastAPI 自带 TLS(通过 uvicorn 配置证书)
|