Mt5Bridge — MT5 HTTP API 网关

通过 HTTP REST API 操控 MetaTrader 5,可部署在 Windows 云服务器上 7×24 运行。


架构

任意语言 (Python / Rust / Node / Go / ...)
         │
         ▼  HTTP REST API (带 API Key 认证)
         │
    Mt5Bridge (C# + MtApi5)  ← 通过端口映射暴露到公网
         │
         ▼  localhost:8228
    MtApi5 EA (MT5 图表上运行)
         │
         ▼
    MetaTrader 5 客户端

前置条件

依赖 说明
.NET 8 SDK 本地编译(只需编译一次)
.NET 8 ASP.NET Core Runtime 部署目标主机上安装
MetaTrader 5 客户端 已登录任意账户
MtApi5 EA 挂载在 MT5 任意图表上,默认监听端口 8228
MtApi5 安装包 安装后生成 MT5Connector.dll 等依赖

一、本地编译

cd Mt5Bridge
dotnet build -c Release

编译产物在 bin\Release\net8.0\,包含以下文件:

文件 说明
Mt5Bridge.exe 可执行入口
Mt5Bridge.dll 编译后的主程序
Mt5Bridge.runtimeconfig.json .NET 运行时配置
Mt5Bridge.deps.json 依赖描述
MtApi5.dll C# 端 MT5 通信库
MtClient.dll MT5 客户端通信库
Newtonsoft.Json.dll JSON 序列化

二、部署到目标主机

1. 安装 .NET 8 Runtime

下载 .NET 8 ASP.NET Core RuntimeWindows x64):https://dotnet.microsoft.com/en-us/download/dotnet/8.0

如果是下载 SDK 压缩包,解压后将内容复制到 C:\Program Files\dotnet\

Copy-Item -Path "解压目录\*" -Destination "C:\Program Files\dotnet\" -Recurse -Force

验证安装:

dotnet --list-runtimes

应看到 Microsoft.NETCore.App 8.0.xMicrosoft.AspNetCore.App 8.0.x

2. 部署文件

bin\Release\net8.0\ 整个文件夹复制到目标主机,例如 C:\Mt5Bridge\

3. 安装 MtApi5

在目标主机上运行 MtApi5 安装包(MSI),这会安装 MT5Connector.dll 等系统级依赖。

4. 挂载 EA

MtApi5.ex5 复制到 MT5 的 MQL5\Experts\ 目录,在 MT5 任意图表上挂载运行。

5. 启动验证

前台运行(调试用,关掉窗口程序就停)

cd C:\Mt5Bridge
dotnet Mt5Bridge.dll

看到以下输出即成功:

CommandTimeout set to 120000ms
Connecting to MT5 via MtApi5 on port 8228...
MT5 Connection: Connected
MT5 Bridge ready on http://localhost:8080

后台运行(7×24 守护,推荐)

cd C:\Mt5Bridge
Start-Process -FilePath "dotnet" -ArgumentList "Mt5Bridge.dll" -WindowStyle Hidden

启动后不弹任何窗口,关掉 PowerShell 也不会停。

关闭后台进程

# 先找 PID
Get-Process -Name dotnet

# 用 PID 杀掉
Stop-Process -Id <PID号> -Force

# 或者一行全杀
Get-Process dotnet -ErrorAction SilentlyContinue | Stop-Process -Force

三、配置 API Key

编辑 Program.cs,修改第 34 行的 API Key

const string API_KEY = "你的随机密码";

生成随机密码:

-join ((48..57) + (65..90) + (97..122) | Get-Random -Count 32 | %{[char]$_})

修改后重新编译,将新的 Mt5Bridge.dll 覆盖到目标主机。

更新 DLL(服务运行时)

Bridge 作为后台服务运行时,文件被锁定无法直接覆盖。需要先停止再覆盖:

# 阻止任务计划再次触发
Stop-ScheduledTask -TaskName "Mt5Bridge"

# 仅结束当前 Bridge 进程
Get-CimInstance Win32_Process |
  Where-Object { $_.Name -eq "dotnet.exe" -and $_.CommandLine -like "*Mt5Bridge.dll*" } |
  Invoke-CimMethod -MethodName Terminate

# 现在可以覆盖 Mt5Bridge.dll 了

# 重新启动
Start-ScheduledTask -TaskName "Mt5Bridge"

说明:

  • 仅更新 Mt5Bridge.dll / Mt5Bridge.exe 这一侧,就会影响 HTTP API、健康检查、参数校验、错误处理、重连逻辑等桥接服务行为。
  • Alpha Trend.ex5 不属于桥接服务本体,不替换也不会影响 /health/account/symbols/rates/from-pos/positions/orders/history/deals/gvar/order/check/order/send/stream/ticks/{symbol}/stream/ticks-sse/{symbol} 这些 API 的正常工作。
  • 只有在你需要新版指标导出逻辑时,才需要同步替换 Alpha Trend.ex5。新版指标变化包括:只输出已收盘 K 线信号,以及使用带周期/参数作用域的 GlobalVariable 名称。

四、端口映射(公网访问)

云服务商端口映射

在云服务商控制台配置端口映射,例如:

字段
类型 TCP
公网端口 13485
内网端口 8080
说明 Mt5Bridge

Windows 防火墙

如果云服务商不自动放通,手动添加防火墙规则:

New-NetFirewallRule -Name "Mt5Bridge" -DisplayName "Mt5Bridge 13485" -Direction Inbound -Protocol TCP -LocalPort 13485 -Action Allow

五、注册为后台服务(开机自启)

使用 Windows 任务计划程序,让 Bridge 开机自动启动、崩溃自动重启。

安装

$action = New-ScheduledTaskAction -Execute "C:\Program Files\dotnet\dotnet.exe" -Argument "Mt5Bridge.dll" -WorkingDirectory "C:\Mt5Bridge"
$trigger = New-ScheduledTaskTrigger -AtStartup
$settings = New-ScheduledTaskSettingsSet -StartWhenAvailable -RestartCount 3 -RestartInterval (New-TimeSpan -Minutes 1)
Register-ScheduledTask -TaskName "Mt5Bridge" -Action $action -Trigger $trigger -Settings $settings
Start-ScheduledTask -TaskName "Mt5Bridge"

管理命令

# 查看状态
Get-ScheduledTask -TaskName "Mt5Bridge" | Get-ScheduledTaskInfo

# 停止
Stop-ScheduledTask -TaskName "Mt5Bridge"

# 重启
Start-ScheduledTask -TaskName "Mt5Bridge"

# 删除
Unregister-ScheduledTask -TaskName "Mt5Bridge" -Confirm:$false

六、API 接口

所有接口均需认证,支持两种方式:

方式一:Header(推荐,适用于代码调用)

X-API-Key: 你的密码

方式二:URL 参数(适用于浏览器直接访问)

?key=你的密码

示例:

http://IP:端口/health?key=你的密码

健康检查

GET /health

响应示例:

{
  "status": "healthy",
  "mt5_connected": true,
  "mt5_version": "unknown",
  "api_version": "1.0.0"
}

当 MT5 断开时,接口会返回 503 Service Unavailable

账户信息

GET /account

响应字段:

字段 类型 说明
login number 账户号
leverage number 杠杆
balance number 余额
equity number 净值
profit number 浮动盈亏
margin number 已用保证金
margin_free number 可用保证金
margin_level number 保证金比例
currency string 账户币种
server string 服务器名
name string 账户名称
company string 经纪商
trade_allowed bool 是否允许交易
trade_expert bool 是否允许 EA 交易

实际响应结构:

{
  "data": [
    {
      "login": 12345678,
      "balance": 10000.0
    }
  ],
  "count": 1,
  "format": "json"
}

品种信息

GET /symbols/{symbol}

bid/ask 从实时 tick 数据获取(自动等待最多 3 秒),避免品种刚加入 Market Watch 时返回 0 的问题。

示例: /symbols/XAUUSDc

响应字段:

字段 类型 说明
name string 品种名称
description string 描述
digits number 小数位数
point number 点值
bid number 卖价
ask number 买价
spread number 点差
spread_float bool 是否浮动点差
volume_min number 最小手数
volume_max number 最大手数
volume_step number 手数步长
trade_contract_size number 合约大小
currency_base string 基础货币
currency_profit string 利润货币
category string 分类路径

实时 Tick

GET /symbols/{symbol}/tick

自动将品种加入 MT5 Market Watch,并等待最多 3 秒获取真实 tick 数据(解决品种未订阅时返回空值的问题)。

示例: /symbols/XAUUSDc/tick

响应字段:

字段 类型 说明
time string 时间
bid number 卖价
ask number 买价
last number 最新成交价
volume number 成交量
time_msc string 毫秒级时间
volume_real number 真实成交量

实时 Tick 推送(WebSocket

WS /stream/ticks/{symbol}

MT5 每收到一条 tick 就立即推给所有订阅者,避免轮询开销。

  • X-API-Key 认证(握手 Header 或 ?key= query 参数)
  • 连接时自动把品种加入 MT5 Market Watch;最后一个订阅者断开时自动移除
  • 同一品种可被多个客户端同时订阅,互不影响
  • 每个品种最多 50 个订阅者(WS + SSE 共用),超出返回 429
  • 每 30 秒发一条心跳包,无 tick 时也发,用于穿透 NAT 保持连接

Python 示例(需 pip install websocket-client):

import websocket, json

ws = websocket.WebSocketApp(
    "ws://你的IP:13485/stream/ticks/XAUUSDc",
    header=["X-API-Key: 你的密码"],
    on_message=lambda ws, msg: print(json.loads(msg)),
)
ws.run_forever()

浏览器示例(用 query 参数传 key):

const ws = new WebSocket("ws://你的IP:13485/stream/ticks/XAUUSDc?key=你的密码");
ws.onmessage = (e) => console.log(JSON.parse(e.data));

推送格式(每条 tick 一帧 JSON):

{
  "type": "tick",
  "symbol": "XAUUSDc",
  "time": "2026-07-08T10:30:45",
  "bid": 4180.0,
  "ask": 4180.5,
  "last": 4180.2,
  "volume": 100,
  "time_msc": "2026-07-08T10:30:45.123000",
  "flags": 6
}

心跳包:{"type":"heartbeat","time":"2026-07-08T10:31:15"}

实时 Tick 推送(SSE,不能用 WebSocket 时)

GET /stream/ticks-sse/{symbol}   →   text/event-stream

面向无法建 WebSocket 的客户端(部分老浏览器、内网代理、curl 等)。

curl -N -H "X-API-Key: 你的密码" http://你的IP:13485/stream/ticks-sse/XAUUSDc

每条 tick 一帧 SSE

data: {"type":"tick","symbol":"XAUUSDc","bid":4180.0,...}

data: {"type":"heartbeat","time":"2026-07-08T10:31:15"}

历史 K 线

GET /rates/from-pos?symbol={symbol}&timeframe={timeframe}&start_pos={start}&count={count}

参数说明:

参数 说明
symbol 品种名称
timeframe 周期:TIMEFRAME_M1 / M5 / M15 / M30 / H1 / H4 / D1
start_pos 起始位置(0=最新)
count 获取数量

示例: /rates/from-pos?symbol=XAUUSDc&timeframe=TIMEFRAME_H1&start_pos=0&count=100

响应字段:

字段 类型 说明
time string 开盘时间
open number 开盘价
high number 最高价
low number 最低价
close number 收盘价
tick_volume number Tick 成交量
spread number 点差
real_volume number 真实成交量

当前持仓

GET /positions[?symbol={symbol}]

symbol 为可选过滤参数。

响应字段:

字段 类型 说明
ticket number 持仓编号
symbol string 品种
type number 类型(0=买, 1=卖)
volume number 手数
price_open number 开仓价
sl number 止损价
tp number 止盈价
price_current number 当前价
swap number 隔夜息
profit number 盈亏
comment string 注释
magic number Magic Number

平仓

POST /position/close
{ "ticket": 12345678 }
{ "ticket": 12345678, "volume": 0.05 }   // 部分平仓
字段 类型 必填 说明
ticket number 持仓编号
volume number 平仓手数;不传/0=全平,>0=部分平仓
deviation number 允许滑点(默认 10

改持仓 SL/TP

POST /position/modify
{ "ticket": 12345678, "sl": 4170.0, "tp": 4190.0 }

sl/tp 设为 0 表示清除。

对冲平仓(节省点差)

POST /position/close-by
{ "position": 111, "position_by": 222 }

两张持仓必须 同品种 + 反向。MT5 用净额结算,只收一次点差。

批量平仓

POST /positions/close-batch
{ "magic": 123456 }
{ "symbol": "XAUUSDc", "magic": 123456 }

symbolmagic 至少传一个。返回 {closed, failed, data:[...]}

移动止损

服务端不做轮询,由客户端结合 /positions 拉取和 /position/modify 实现:

while True:
    for p in bridge.positions():
        cur = p["price_current"]
        new_sl = cur - 50 if p["type"] == 0 else cur + 50
        if abs(new_sl - p["sl"]) >= 10:
            bridge.modify_position(p["ticket"], sl=new_sl)
    time.sleep(1)

也可订阅 WebSocket tick 流(/stream/ticks/{symbol}),按 tick 回调触发,更实时。

挂单

GET /orders?symbol={symbol}

symbol 为可选参数,不传则返回所有挂单。

撤单

POST /order/cancel
{ "ticket": 87654321 }

改挂单

POST /order/modify
{ "ticket": 87654321, "price": 4180.0, "sl": 4170.0, "tp": 4190.0 }

订单预检

POST /order/check

填充模式自动适配:服务端会根据品种的 SYMBOL_FILLING_MODE 自动选择经纪商支持的填充模式。如果请求的 type_filling 不被支持,会按 IOC(1) → FOK(0) → RETURN(2) 顺序降级,无需客户端手动判断。

请求体:

{
  "action": 1,
  "symbol": "XAUUSDc",
  "volume": 0.01,
  "order_type": 0,
  "price": 4180.0,
  "sl": 4170.0,
  "tp": 4190.0,
  "magic": 123456,
  "comment": "test",
  "deviation": 10,
  "type_filling": 0
}
字段 类型 说明
action number 交易操作类型
symbol string 品种
volume number 手数
order_type number 订单类型
price number 价格
sl number 止损
tp number 止盈
magic number Magic Number
comment string 注释
deviation number 偏差
type_filling number 填充模式:0=FOK, 1=IOC, 2=RETURN(自动适配,不传也行)

type_filling 说明:

含义 说明
0 FOK (Fill or Kill) 必须全部成交,否则取消
1 IOC (Immediate or Cancel) 能成交多少成交多少
2 RETURN 剩余部分留在订单簿

不同经纪商支持的填充模式不同(如 ICMarkets 只支持 IOC),服务端会自动降级,客户端无需关心。

下单

POST /order/send

/order/check 相同,type_filling 会自动适配经纪商支持的填充模式。

请求体:

{
  "request": {
    "action": 1,
    "symbol": "XAUUSDc",
    "volume": 0.01,
    "order_type": 0,
    "price": 4180.0,
    "sl": 4170.0,
    "tp": 4190.0,
    "magic": 123456,
    "comment": "test",
    "deviation": 10,
    "type_filling": 0
  }
}

历史成交

GET /history/deals?date_from={from}&date_to={to}&symbol={symbol}

示例: /history/deals?date_from=2026-07-01&date_to=2026-07-03&symbol=XAUUSDc

全局变量(MQL5 信号桥)

让 MQL5 指标/EA 将信号写入 GlobalVariablePython 通过 Bridge 读取。无需翻译 MQL5 代码。

GET /gvar
GET /gvar/{name}
POST /gvar/{name}
DELETE /gvar/{name}

列出所有全局变量:

GET /gvar

读取指定变量:

GET /gvar/{name}

写入变量:

POST /gvar/{name}
Body: {"value": 75.5}

删除变量:

DELETE /gvar/{name}

MQL5 侧(仅在你要升级指标信号导出逻辑时才需要修改):

int last_closed = rates_total - 2;
string key = StringFormat("MY_SIGNAL_%s_%s", _Symbol, EnumToString(_Period));
GlobalVariableSet(key, Alpha[last_closed]);

如果你没有替换新版 Alpha Trend.ex5,远程 /gvar 中仍会看到旧键名,例如:

AT_Alpha_XAUUSDc
AT_Buy_XAUUSDc
AT_Offset_XAUUSDc
AT_Sell_XAUUSDc
AT_Trend_XAUUSDc

这不影响桥接 API 本身,只表示 MT5 端仍在运行旧版指标。

Python 侧读取:

resp = requests.get(f"{BRIDGE}/gvar/MY_SIGNAL_XAUUSDc", headers=HEADERS)
signal = resp.json()["value"]

七、调用示例

浏览器

直接在地址栏输入(带 ?key= 参数):

http://IP:端口/health?key=你的密码
http://IP:端口/account?key=你的密码
http://IP:端口/symbols/XAUUSDc/tick?key=你的密码

PowerShell

# 健康检查
Invoke-RestMethod -Uri "http://IP:端口/health" -Headers @{"X-API-Key"="你的密码"}

# 账户信息
Invoke-RestMethod -Uri "http://IP:端口/account" -Headers @{"X-API-Key"="你的密码"}

# 实时行情
Invoke-RestMethod -Uri "http://IP:端口/symbols/XAUUSDc/tick" -Headers @{"X-API-Key"="你的密码"}

# 获取 100 根 H1 K 线
Invoke-RestMethod -Uri "http://IP:端口/rates/from-pos?symbol=XAUUSDc&timeframe=TIMEFRAME_H1&start_pos=0&count=100" -Headers @{"X-API-Key"="你的密码"}

Python

import requests

BRIDGE = "http://IP:端口"
HEADERS = {"X-API-Key": "你的密码"}

# 健康检查
resp = requests.get(f"{BRIDGE}/health", headers=HEADERS)
print(resp.json())

# 账户信息
resp = requests.get(f"{BRIDGE}/account", headers=HEADERS)
print(resp.json())

# 实时行情
resp = requests.get(f"{BRIDGE}/symbols/XAUUSDc/tick", headers=HEADERS)
tick = resp.json()
print(f"Bid: {tick['data'][0]['bid']}, Ask: {tick['data'][0]['ask']}")

# 获取 K 线
resp = requests.get(f"{BRIDGE}/rates/from-pos", headers=HEADERS, params={
    "symbol": "XAUUSDc",
    "timeframe": "TIMEFRAME_H1",
    "start_pos": 0,
    "count": 100
})
print(resp.json())

# 下单
resp = requests.post(f"{BRIDGE}/order/send", headers=HEADERS, json={
    "request": {
        "action": 1,
        "symbol": "XAUUSDc",
        "volume": 0.01,
        "order_type": 0,
        "price": 4180.0,
        "sl": 4170.0,
        "tp": 4190.0,
        "magic": 123456,
        "comment": "test",
        "deviation": 10,
        "type_filling": 0
    }
})
print(resp.json())

curl

# 健康检查
curl -H "X-API-Key: 你的密码" http://IP:端口/health

# 账户信息
curl -H "X-API-Key: 你的密码" http://IP:端口/account

# 下单
curl -X POST http://IP:端口/order/send \
  -H "Content-Type: application/json" \
  -H "X-API-Key: 你的密码" \
  -d '{"request":{"action":1,"symbol":"XAUUSDc","volume":0.01,"order_type":0,"price":4180.0,"sl":4170.0,"tp":4190.0,"magic":123456,"comment":"test","deviation":10,"type_filling":0}}'

八、迁移到新主机

需要复制的内容

从哪里 复制什么 放到哪里
本地 bin\Release\net8.0\ 整个文件夹 新主机 C:\Mt5Bridge\
MtApi5 安装包 运行 MSI 安装 新主机
MtApi5 项目 MtApi5.ex5 新主机 MT5 的 MQL5\Experts\

新主机操作步骤

  1. 安装 .NET 8 ASP.NET Core Runtime
  2. 运行 MtApi5 MSI 安装包
  3. 复制 bin\Release\net8.0\C:\Mt5Bridge\
  4. 复制 MtApi5.ex5 到 MT5 Experts 目录
  5. 在 MT5 图表上挂载 MtApi5 EA
  6. 配置云服务商端口映射(如需要外网访问)
  7. 配置 Windows 防火墙
  8. 注册任务计划程序实现开机自启
  9. 验证:Invoke-RestMethod -Uri "http://localhost:8080/health" -Headers @{"X-API-Key"="密码"}

九、常用维护命令

# 查看 Bridge 是否在运行
Get-ScheduledTask -TaskName "Mt5Bridge" | Get-ScheduledTaskInfo

# 查看是否在监听端口
netstat -ano | findstr 8080

# 查看 .NET 运行时版本
dotnet --list-runtimes

# 手动启动 Bridge(前台调试)
cd C:\Mt5Bridge
dotnet Mt5Bridge.dll

# 杀死 Bridge 进程
Stop-ScheduledTask -TaskName "Mt5Bridge"

十、安全建议

  1. API Key 必须修改:部署前把默认的 mt5bridge-2024-secret-key 改成随机字符串
  2. 端口号不要用默认的:当前使用 8080,如要更换建议用 10000 以上的随机端口
  3. 防火墙白名单:如果只有固定 IP 访问,在云服务商安全组里限制来源 IP
  4. 不要用 HTTP 明文传输敏感数据:可配合 Nginx Proxy Manager 加 HTTPS
  5. 定期更换 API Key:修改 Program.cs 中的 Key 后重新编译部署
S
Description
No description provided
Readme 2.7 MiB
Languages
C# 65.1%
Python 19.6%
MQL5 15.3%