动机
很简单:我想在聊天软件里直接给 MT5 下单。
不是打开 MT5 客户端,不是点鼠标,而是像发消息一样:
下单 0.01 手 XAUUSD 多单平仓查持仓要做到这一点,需要打通几层:
- OpenClaw
→ 聊天软件入口 - Windows HTTP Skill
→ 控制 Windows 节点 - Python 脚本
→ 调用 MT5 API - MT5
→ 执行交易
这篇文章只记录第一、二步:如何搭建 Windows 操控能力。
不谈策略,不谈指标,不谈高大上的架构。
就是实实在在的记录:怎么让 OpenClaw 能控制 Windows,进而控制 MT5。
一、Windows 节点架构
设计思路
Windows 端运行一个 HTTP 服务(端口 8080),OpenClaw 通过 HTTP 请求调用 Windows 的能力。
┌─────────────┐ HTTP + Basic Auth ┌─────────────┐│ OpenClaw │ ───────────────────────→ │ Windows ││ (Linux) │ ← ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ │ (192.168.2.99)│└─────────────┘ JSON 响应 └─────────────┘认证方式
- Base URL
: http://192.168.2.99:8080 - 认证
: Basic Auth,默认 openclaw:openclaw - 响应格式
: 统一 JSON
// 成功{ "ok": true, "data": {...}, "meta": {"requestId": "...", "ts": 1234567890}}// 失败{ "ok": false, "error": {"code": "...", "message": "..."}, "meta": {...}}二、核心接口
1. 读取类接口
GET /api/state/foreground | ||
GET /api/state/windows | ||
GET /api/state/processes | ||
GET /api/state/snapshot | ||
GET /api/state/clipboard |
示例:获取前台窗口
curl -u openclaw:openclaw "http://192.168.2.99:8080/api/state/foreground"响应:
{ "ok": true, "data": { "windowTitle": "104669867 - MetaQuotes-Demo: 模拟账户 - Hedge - [XAUUSD,M1]", "processName": "terminal64.exe", "pid": 9944 }}这说明 MT5 正在运行,当前品种是 XAUUSD,周期 M1。
2. 执行类接口
POST /api/screen/click | {"x":500,"y":300} | |
POST /api/input/key | {"key":"F9"} | |
POST /api/input/text | {"text":"hello"} | |
POST /api/app/launch_async | {"path":"notepad.exe"} | |
POST /api/window/action | {"action":"activate","titleContains":"MetaTrader"} |
示例:按 F9 打开 MT5 订单窗口
curl -u openclaw:openclaw -X POST -H "Content-Type: application/json" \ -d '{"key":"F9"}' "http://192.168.2.99:8080/api/input/key"3. 文件系统接口
GET /api/fs/list?path= | ||
GET /api/fs/read?path= | ||
POST /api/fs/write | ||
POST /api/fs/mkdir |
沙箱机制:
环境变量 OPENCLAW_FS_ROOT指定根目录未设置时默认为服务启动时的工作目录 禁止通过 ..逃出根目录单文件读写上限 16MiB
三、实际踩坑记录
坑 1:截图是黑的
现象: 调用 /api/state/snapshot 返回了图片,但打开是全黑。
原因: Windows 锁屏或远程桌面会话未激活,截图抓到的是黑屏。
解决: 确保 Windows 处于登录状态,桌面会话活跃。
坑 2:Python 路径问题
现象: 执行 python3 script.py 失败,提示找不到命令。
原因: Windows 上 python3 可能不在 PATH 中,或者有多个 Python 版本。
解决: 使用绝对路径:
# 错误{"cmd": "python3 C:\\scripts\\mt5_order.py"}# 正确{"cmd": "C:\\Python311\\python.exe C:\\scripts\\mt5_order.py"}坑 3:命令参数被拆分
现象: 带空格的脚本路径执行失败。
原因: 命令被按空格拆分,路径 C:\Program Files\... 被拆成多段。
解决: 使用 cmd 模式,整体执行:
# 错误(路径被拆分){"cmd": "python C:\\Program Files\\script.py"}# 正确(用 cmd /c 整体执行){"cmd": "cmd /c \"python C:\\Program Files\\script.py\""}坑 4:MT5 自动交易未启用
现象: EA 不执行交易,脚本下单无响应。
原因: MT5 的"允许算法交易"开关未打开。
解决:
MT5 菜单栏 → 工具 → 选项 → EA 勾选"允许算法交易" 图表右上角确认自动交易图标是绿色
坑 5:Base64 图片不是真图片
现象: 截图返回的是 Base64 字符串,直接保存打不开。
原因: API 返回的是 data.base64 字段,需要解码。
解决: Python 解码示例:
import base64# 假设 response 是 API 返回的 JSONbase64_data = response['data']['base64']image_bytes = base64.b64decode(base64_data)with open('snapshot.jpg', 'wb') as f: f.write(image_bytes)四、Python 脚本示例
1. 读取 MT5 持仓
# C:\scripts\mt5_positions.pyimport MetaTrader5 as mt5import jsonmt5.initialize()positions = mt5.positions_get()if positions: result = [] for pos in positions: result.append({ 'symbol': pos.symbol, 'type': 'BUY' if pos.type == 0 else 'SELL', 'volume': pos.volume, 'price_open': pos.price_open, 'profit': pos.profit }) print(json.dumps(result, indent=2))else: print("[]")mt5.shutdown()通过 Windows skill 执行:
curl -u openclaw:openclaw -X POST -H "Content-Type: application/json" \ -d '{"cmd": "C:\\Python311\\python.exe C:\\scripts\\mt5_positions.py"}' \ "http://192.168.2.99:8080/api/app/launch_async"2. 市价下单
# C:\scripts\mt5_buy.pyimport MetaTrader5 as mt5mt5.initialize()symbol = "XAUUSD"volume = 0.01price = mt5.symbol_info_tick(symbol).askrequest = { "action": mt5.TRADE_ACTION_DEAL, "symbol": symbol, "volume": volume, "type": mt5.ORDER_TYPE_BUY, "price": price, "deviation": 10, "magic": 234000, "comment": "OpenClaw order", "type_time": mt5.ORDER_TIME_GTC, "type_filling": mt5.ORDER_FILLING_IOC,}result = mt5.order_send(request)print(f"Order result: {result}")mt5.shutdown()3. 读取账户状态
# C:\scripts\mt5_account.pyimport MetaTrader5 as mt5mt5.initialize()info = mt5.account_info()if info: print(f"Login: {info.login}") print(f"Balance: {info.balance}") print(f"Equity: {info.equity}") print(f"Margin: {info.margin}") print(f"Free Margin: {info.margin_free}")mt5.shutdown()五、OpenClaw 侧的封装
在 OpenClaw 侧,我用一个 Shell 脚本封装常用操作:
#!/bin/bash# mt5-controller.shBASE_URL="http://192.168.2.99:8080"AUTH="openclaw:openclaw"send_key() { curl -s -u "$AUTH" -X POST -H "Content-Type: application/json" \ -d "{\"key\":\"$1\"}" "$BASE_URL/api/input/key"}send_text() { curl -s -u "$AUTH" -X POST -H "Content-Type: application/json" \ -d "{\"text\":\"$1\"}" "$BASE_URL/api/input/text"}activate_window() { curl -s -u "$AUTH" -X POST -H "Content-Type: application/json" \ -d "{\"action\":\"activate\",\"titleContains\":\"MetaTrader\"}" \ "$BASE_URL/api/window/action"}# 下单函数action_order() { local lots="${1:-0.01}" activate_window send_key "F9" sleep 0.3 send_key "Tab" send_key "Tab" send_text "$lots" send_key "Enter"}case "$1" in order) action_order "$2" ;; close) action_close_all ;; symbol) action_symbol "$2" ;; *) echo "用法: $0 {order|close|symbol} [args]" ;;esac使用:
./mt5-controller.sh order 0.01 # 下单 0.01 手./mt5-controller.sh symbol BTCUSD # 切换品种./mt5-controller.sh close # 平仓六、当前能力清单
已实现 ✅
待实现 ⏳
七、下一步
这篇文章只记录了Windows 操控能力的搭建过程。
下一步要做的:
- 封装成 OpenClaw Skill
- 让聊天软件直接调用 - 自然语言解析
- 把"买 0.01 手黄金"转成 API 调用 - 订单确认机制
- 大额订单需要二次确认 - 交易日志
- 记录每笔操作的来源和时间
八、核心代码位置
/home/user/.openclaw/workspace/├── mt5-controller/│ ├── mt5-controller.sh # OpenClaw 侧控制器│ └── mt5-shortcuts.md # MT5 快捷键手册└── temp/2026-03-21/mt5-trade/ ├── 001_buy_xauusd.py # 第一个买单脚本 ├── 002_check_positions.py # 持仓查询 ├── 003_account_status.py # 账户状态 └── 008_final_buy.py # 最终版本买单脚本Windows 侧脚本在:
C:\scripts\├── mt5_buy.py├── mt5_sell.py├── mt5_positions.py└── mt5_account.py结尾
这篇文章没什么高大上的东西。
就是实实在在记录:
怎么搭 Windows HTTP 服务 怎么通过 HTTP 控制 Windows 怎么用 Python 调用 MT5 API 遇到了哪些坑,怎么填的
下一步,我会把这些能力封装成 OpenClaw 的 Skill,让聊天软件真的能下单。
那时候再写第二篇:《OpenClaw MT5 自动化交易二:自然语言下单》。
核心一句话: 这个系统的价值不是预测行情,而是让普通人可以通过聊天软件触达自动交易能力,降低术语门槛,帮助"祛魅"。
夜雨聆风