From 17ee7418db2cb5844ed378e50486c832fb71e825 Mon Sep 17 00:00:00 2001 From: gavindiaz Date: Fri, 3 Jul 2026 17:45:43 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0API=E4=BD=BF=E7=94=A8?= =?UTF-8?q?=E6=8C=87=E5=8D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- API使用指南.md | 483 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 483 insertions(+) create mode 100644 API使用指南.md diff --git a/API使用指南.md b/API使用指南.md new file mode 100644 index 0000000..2a462d5 --- /dev/null +++ b/API使用指南.md @@ -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`。 \ No newline at end of file