添加API使用指南
This commit is contained in:
+483
@@ -0,0 +1,483 @@
|
||||
# Mt5Bridge API 使用指南
|
||||
|
||||
> 本文档面向**开发者**,假设 Bridge 已在云端部署运行。直接复制代码即可使用。
|
||||
|
||||
---
|
||||
|
||||
## 连接信息
|
||||
|
||||
| 项目 | 值 |
|
||||
|------|-----|
|
||||
| 地址 | `http://61.164.252.86:13485` |
|
||||
| 认证 | `X-API-Key` Header 或 `?key=` URL 参数 |
|
||||
| 格式 | 所有返回均为 JSON |
|
||||
|
||||
---
|
||||
|
||||
## 快速开始(Python)
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
BRIDGE = "http://61.164.252.86:13485"
|
||||
KEY = "your-api-key"
|
||||
|
||||
def api(path, params=None):
|
||||
"""统一请求封装"""
|
||||
resp = requests.get(f"{BRIDGE}{path}", params=params, headers={"X-API-Key": KEY})
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
def api_post(path, data):
|
||||
"""POST 请求封装"""
|
||||
resp = requests.post(f"{BRIDGE}{path}", json=data, headers={"X-API-Key": KEY})
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
# 测试连接
|
||||
print(api("/health"))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API 接口速查
|
||||
|
||||
### 1. 健康检查
|
||||
|
||||
```
|
||||
GET /health
|
||||
```
|
||||
|
||||
```python
|
||||
status = api("/health")
|
||||
# {"status": "healthy", "mt5_connected": true, "api_version": "1.0.0"}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 2. 账户信息
|
||||
|
||||
```
|
||||
GET /account
|
||||
```
|
||||
|
||||
```python
|
||||
acc = api("/account")["data"][0]
|
||||
print(f"余额: {acc['balance']}, 净值: {acc['equity']}, 浮动盈亏: {acc['profit']}")
|
||||
print(f"保证金: {acc['margin']}, 可用保证金: {acc['margin_free']}, 比例: {acc['margin_level']}%")
|
||||
print(f"杠杆: 1:{acc['leverage']}, 币种: {acc['currency']}")
|
||||
```
|
||||
|
||||
**返回字段:**
|
||||
|
||||
| 字段 | 含义 |
|
||||
|------|------|
|
||||
| login | 账户号 |
|
||||
| balance | 余额 |
|
||||
| equity | 净值 |
|
||||
| profit | 浮动盈亏 |
|
||||
| margin | 已用保证金 |
|
||||
| margin_free | 可用保证金 |
|
||||
| margin_level | 保证金比例 |
|
||||
| leverage | 杠杆 |
|
||||
| currency | 账户币种 |
|
||||
| trade_allowed | 是否允许交易 |
|
||||
| trade_expert | 是否允许 EA 交易 |
|
||||
|
||||
---
|
||||
|
||||
### 3. 实时行情
|
||||
|
||||
```
|
||||
GET /symbols/{symbol}/tick
|
||||
```
|
||||
|
||||
```python
|
||||
def get_tick(symbol):
|
||||
data = api(f"/symbols/{symbol}/tick")["data"][0]
|
||||
return data["bid"], data["ask"]
|
||||
|
||||
bid, ask = get_tick("XAUUSDc")
|
||||
print(f"XAUUSD Bid: {bid} Ask: {ask} Spread: {ask - bid}")
|
||||
```
|
||||
|
||||
**返回字段:**
|
||||
|
||||
| 字段 | 含义 |
|
||||
|------|------|
|
||||
| bid | 卖价 |
|
||||
| ask | 买价 |
|
||||
| last | 最新成交价 |
|
||||
| volume | 成交量 |
|
||||
| time | 时间 |
|
||||
|
||||
---
|
||||
|
||||
### 4. 品种信息
|
||||
|
||||
```
|
||||
GET /symbols/{symbol}
|
||||
```
|
||||
|
||||
```python
|
||||
def get_symbol_info(symbol):
|
||||
info = api(f"/symbols/{symbol}")["data"][0]
|
||||
print(f"品种: {info['name']}, 描述: {info['description']}")
|
||||
print(f"小数位: {info['digits']}, 点值: {info['point']}")
|
||||
print(f"最小手数: {info['volume_min']}, 最大: {info['volume_max']}, 步长: {info['volume_step']}")
|
||||
print(f"合约大小: {info['trade_contract_size']}")
|
||||
return info
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5. 历史 K 线
|
||||
|
||||
```
|
||||
GET /rates/from-pos?symbol={symbol}&timeframe={timeframe}&start_pos={start}&count={count}
|
||||
```
|
||||
|
||||
| 参数 | 可选值 |
|
||||
|------|--------|
|
||||
| timeframe | `TIMEFRAME_M1` / `M5` / `M15` / `M30` / `H1` / `H4` / `D1` |
|
||||
| start_pos | 0 = 最新,1 = 前一根,以此类推 |
|
||||
| count | 获取数量 |
|
||||
|
||||
```python
|
||||
import pandas as pd
|
||||
|
||||
def get_rates(symbol, timeframe, count):
|
||||
"""获取 K 线并转为 DataFrame"""
|
||||
data = api("/rates/from-pos", params={
|
||||
"symbol": symbol,
|
||||
"timeframe": f"TIMEFRAME_{timeframe}",
|
||||
"start_pos": 0,
|
||||
"count": count
|
||||
})["data"]
|
||||
df = pd.DataFrame(data)
|
||||
df["time"] = pd.to_datetime(df["time"])
|
||||
df.set_index("time", inplace=True)
|
||||
return df
|
||||
|
||||
# 获取最近 100 根 H1 K 线
|
||||
df = get_rates("XAUUSDc", "H1", 100)
|
||||
print(df.head())
|
||||
```
|
||||
|
||||
**返回字段:** `time`, `open`, `high`, `low`, `close`, `tick_volume`, `spread`, `real_volume`
|
||||
|
||||
---
|
||||
|
||||
### 6. 当前持仓
|
||||
|
||||
```
|
||||
GET /positions
|
||||
```
|
||||
|
||||
```python
|
||||
def get_positions():
|
||||
return api("/positions")["data"]
|
||||
|
||||
positions = get_positions()
|
||||
for pos in positions:
|
||||
print(f"{pos['ticket']} {pos['symbol']} "
|
||||
f"{'买' if pos['type'] == 0 else '卖'} "
|
||||
f"手数:{pos['volume']} 盈亏:{pos['profit']}")
|
||||
```
|
||||
|
||||
**返回字段:** `ticket`, `symbol`, `type`(0=买,1=卖), `volume`, `price_open`, `sl`, `tp`, `price_current`, `swap`, `profit`, `comment`, `magic`
|
||||
|
||||
---
|
||||
|
||||
### 7. 挂单
|
||||
|
||||
```
|
||||
GET /orders?symbol={symbol}
|
||||
```
|
||||
|
||||
symbol 可选,不传返回全部。
|
||||
|
||||
```python
|
||||
orders = api("/orders")["data"]
|
||||
for o in orders:
|
||||
print(f"{o['ticket']} {o['symbol']} 类型:{o['type']} 手数:{o['volume_initial']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 8. 订单预检
|
||||
|
||||
```
|
||||
POST /order/check
|
||||
```
|
||||
|
||||
下单前验证,不会真正执行。检查保证金是否足够、价格是否有效等。
|
||||
|
||||
```python
|
||||
def check_order(symbol, volume, order_type, price, sl=None, tp=None, magic=0, comment=""):
|
||||
"""预检订单"""
|
||||
data = {
|
||||
"action": 1, # 1=即时成交
|
||||
"symbol": symbol,
|
||||
"volume": volume,
|
||||
"order_type": order_type, # 0=市价买, 1=市价卖
|
||||
"price": price,
|
||||
"sl": sl or 0,
|
||||
"tp": tp or 0,
|
||||
"magic": magic,
|
||||
"comment": comment,
|
||||
"deviation": 10
|
||||
}
|
||||
result = api_post("/order/check", data)["data"]
|
||||
print(f"预检结果: retcode={result['retcode']}, comment={result['comment']}")
|
||||
if result['retcode'] == 0:
|
||||
print("✅ 可以下单")
|
||||
else:
|
||||
print("❌ 不可下单")
|
||||
return result
|
||||
|
||||
check_order("XAUUSDc", 0.01, 0, 4180.0, sl=4170.0, tp=4190.0)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 9. 下单
|
||||
|
||||
```
|
||||
POST /order/send
|
||||
```
|
||||
|
||||
```python
|
||||
def send_order(symbol, volume, order_type, price, sl=None, tp=None, magic=0, comment=""):
|
||||
"""下单"""
|
||||
data = {
|
||||
"request": {
|
||||
"action": 1,
|
||||
"symbol": symbol,
|
||||
"volume": volume,
|
||||
"order_type": order_type,
|
||||
"price": price,
|
||||
"sl": sl or 0,
|
||||
"tp": tp or 0,
|
||||
"magic": magic,
|
||||
"comment": comment,
|
||||
"deviation": 10
|
||||
}
|
||||
}
|
||||
result = api_post("/order/send", data)["data"]
|
||||
print(f"下单结果: retcode={result['retcode']}, order={result['order']}, comment={result['comment']}")
|
||||
return result
|
||||
|
||||
# 市价买入 0.01 手 XAUUSD
|
||||
result = send_order("XAUUSDc", 0.01, 0, 4180.0, sl=4170.0, tp=4190.0)
|
||||
```
|
||||
|
||||
**order_type 说明:**
|
||||
|
||||
| 值 | 含义 |
|
||||
|------|------|
|
||||
| 0 | 市价买入 |
|
||||
| 1 | 市价卖出 |
|
||||
| 2 | 限价买入 |
|
||||
| 3 | 限价卖出 |
|
||||
| 4 | 止损买入 |
|
||||
| 5 | 止损卖出 |
|
||||
|
||||
---
|
||||
|
||||
### 10. 历史成交
|
||||
|
||||
```
|
||||
GET /history/deals?date_from={from}&date_to={to}&symbol={symbol}
|
||||
```
|
||||
|
||||
```python
|
||||
deals = api("/history/deals", params={
|
||||
"date_from": "2026-07-01",
|
||||
"date_to": "2026-07-03",
|
||||
"symbol": "XAUUSDc"
|
||||
})["data"]
|
||||
|
||||
for d in deals:
|
||||
print(f"{d['ticket']} {d['time']} {d['symbol']} "
|
||||
f"手数:{d['volume']} 价格:{d['price']} 盈亏:{d['profit']}")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 完整策略模板
|
||||
|
||||
```python
|
||||
import requests
|
||||
import pandas as pd
|
||||
import time
|
||||
from datetime import datetime
|
||||
|
||||
BRIDGE = "http://61.164.252.86:13485"
|
||||
KEY = "your-api-key"
|
||||
|
||||
class Mt5Bridge:
|
||||
def __init__(self):
|
||||
self.headers = {"X-API-Key": KEY}
|
||||
|
||||
def _get(self, path, params=None):
|
||||
r = requests.get(f"{BRIDGE}{path}", params=params, headers=self.headers)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
def _post(self, path, data):
|
||||
r = requests.post(f"{BRIDGE}{path}", json=data, headers=self.headers)
|
||||
r.raise_for_status()
|
||||
return r.json()
|
||||
|
||||
# ── 行情 ──
|
||||
def tick(self, symbol):
|
||||
d = self._get(f"/symbols/{symbol}/tick")["data"][0]
|
||||
return d["bid"], d["ask"]
|
||||
|
||||
def rates(self, symbol, timeframe, count):
|
||||
return self._get("/rates/from-pos", params={
|
||||
"symbol": symbol, "timeframe": f"TIMEFRAME_{timeframe}",
|
||||
"start_pos": 0, "count": count
|
||||
})["data"]
|
||||
|
||||
def to_df(self, symbol, timeframe, count):
|
||||
df = pd.DataFrame(self.rates(symbol, timeframe, count))
|
||||
df["time"] = pd.to_datetime(df["time"])
|
||||
df.set_index("time", inplace=True)
|
||||
return df
|
||||
|
||||
# ── 账户 ──
|
||||
def account(self):
|
||||
return self._get("/account")["data"][0]
|
||||
|
||||
# ── 持仓 ──
|
||||
def positions(self):
|
||||
return self._get("/positions")["data"]
|
||||
|
||||
def has_position(self, symbol):
|
||||
return any(p["symbol"] == symbol for p in self.positions())
|
||||
|
||||
# ── 下单 ──
|
||||
def buy(self, symbol, volume, price, sl=0, tp=0, magic=0, comment=""):
|
||||
return self._send(symbol, volume, 0, price, sl, tp, magic, comment)
|
||||
|
||||
def sell(self, symbol, volume, price, sl=0, tp=0, magic=0, comment=""):
|
||||
return self._send(symbol, volume, 1, price, sl, tp, magic, comment)
|
||||
|
||||
def _send(self, symbol, volume, order_type, price, sl, tp, magic, comment):
|
||||
return self._post("/order/send", {
|
||||
"request": {
|
||||
"action": 1, "symbol": symbol, "volume": volume,
|
||||
"order_type": order_type, "price": price,
|
||||
"sl": sl, "tp": tp, "magic": magic,
|
||||
"comment": comment, "deviation": 10
|
||||
}
|
||||
})["data"]
|
||||
|
||||
def check(self, symbol, volume, order_type, price, sl=0, tp=0):
|
||||
return self._post("/order/check", {
|
||||
"action": 1, "symbol": symbol, "volume": volume,
|
||||
"order_type": order_type, "price": price,
|
||||
"sl": sl, "tp": tp, "magic": 0, "comment": "", "deviation": 10
|
||||
})["data"]
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════
|
||||
# 策略示例:均线金叉死叉
|
||||
# ══════════════════════════════════════════════
|
||||
|
||||
class MAStrategy:
|
||||
def __init__(self, bridge, symbol, fast=20, slow=60):
|
||||
self.bridge = bridge
|
||||
self.symbol = symbol
|
||||
self.fast = fast
|
||||
self.slow = slow
|
||||
|
||||
def signal(self):
|
||||
"""计算信号:1=买入, -1=卖出, 0=观望"""
|
||||
df = self.bridge.to_df(self.symbol, "H1", self.slow + 5)
|
||||
df["ma_fast"] = df["close"].rolling(self.fast).mean()
|
||||
df["ma_slow"] = df["close"].rolling(self.slow).mean()
|
||||
|
||||
# 最新两根 K 线
|
||||
prev = df.iloc[-2]
|
||||
curr = df.iloc[-1]
|
||||
|
||||
# 金叉
|
||||
if prev["ma_fast"] <= prev["ma_slow"] and curr["ma_fast"] > curr["ma_slow"]:
|
||||
return 1
|
||||
# 死叉
|
||||
if prev["ma_fast"] >= prev["ma_slow"] and curr["ma_fast"] < curr["ma_slow"]:
|
||||
return -1
|
||||
return 0
|
||||
|
||||
def run(self):
|
||||
sig = self.signal()
|
||||
bid, ask = self.bridge.tick(self.symbol)
|
||||
acc = self.bridge.account()
|
||||
print(f"[{datetime.now()}] {self.symbol} Bid:{bid} Ask:{ask} "
|
||||
f"Balance:{acc['balance']} Equity:{acc['equity']} Signal:{sig}")
|
||||
|
||||
if sig == 1 and not self.bridge.has_position(self.symbol):
|
||||
print(" → 金叉,开多")
|
||||
self.bridge.buy(self.symbol, 0.01, ask, sl=ask - 50, tp=ask + 100)
|
||||
elif sig == -1 and not self.bridge.has_position(self.symbol):
|
||||
print(" → 死叉,开空")
|
||||
self.bridge.sell(self.symbol, 0.01, bid, sl=bid + 50, tp=bid - 100)
|
||||
|
||||
|
||||
# ══════════════════════════════════════════════
|
||||
# 运行
|
||||
# ══════════════════════════════════════════════
|
||||
|
||||
if __name__ == "__main__":
|
||||
bridge = Mt5Bridge()
|
||||
strategy = MAStrategy(bridge, "XAUUSDc", fast=20, slow=60)
|
||||
|
||||
while True:
|
||||
try:
|
||||
strategy.run()
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
time.sleep(60) # 每分钟检查一次
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 浏览器快速验证
|
||||
|
||||
在浏览器地址栏直接输入:
|
||||
|
||||
```
|
||||
http://61.164.252.86:13485/health?key=your-api-key
|
||||
http://61.164.252.86:13485/account?key=your-api-key
|
||||
http://61.164.252.86:13485/symbols/XAUUSDc/tick?key=your-api-key
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PowerShell 快速测试
|
||||
|
||||
```powershell
|
||||
$key = "your-api-key"
|
||||
Invoke-RestMethod "http://61.164.252.86:13485/health?key=$key"
|
||||
Invoke-RestMethod "http://61.164.252.86:13485/account?key=$key"
|
||||
Invoke-RestMethod "http://61.164.252.86:13485/symbols/XAUUSDc/tick?key=$key"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 返回 "Unauthorized"
|
||||
API Key 错误或没带。检查 Header 中的 `X-API-Key` 或 URL 中的 `?key=`。
|
||||
|
||||
### 返回 "对于该符号,不支持市场执行"
|
||||
`order_type` 填错了,MT5 中有些品种不支持市价单,有些不支持挂单。先调用 `/order/check` 预检。
|
||||
|
||||
### 返回 "没有足够的资金"
|
||||
保证金不足,减小手数或检查 `account.margin_free`。
|
||||
|
||||
### 返回 "无法连接到远程服务器"
|
||||
Bridge 未运行或网络不通,先检查 `/health`。
|
||||
Reference in New Issue
Block a user