Files
sanguo_vnpy_v2/docs/superpowers/specs/2026-07-10-phase3d-live-trading-design.md
T

184 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase 3D 实盘交易集成设计(miniQMT bridge 架构)
> 日期:2026-07-10 | 状态:设计中(网络层已完成,bridge/编排待开发)
> 前序:Phase 3C 模拟盘(PaperEngine 双源+双层记账,commit 1646903/0656108 已完成)
> 关联:[[khquant-analysis]]xtquant 参考)、vps-access skill、`docs/data-platform/daily-update-design.md`
---
## 1. 背景与目标
C 期模拟盘已端到端跑通(PaperEngineraw/qfq 双源 + 总账/分户双层记账 + 软限额 + 占用成本 + 分红送股)。D 期目标:**接入实盘**,实现「模拟→实盘」同引擎切换。
核心约束(决定架构):
- **miniQMT 仅 Windows 桌面**,必须登录常驻,提供 `xtquant` Python API
- **sanguo 跑 NAS Linux Docker 容器**`sanguo_vnpy_v2`
- **Windows 与 NAS 在不同网络**(异地),需跨网打通
- 实走为**日线级**(每日 20:30 单根 bar 推进),对延迟不敏感
→ 结论:唯一可行路径是 **miniQMTxtquant**PTrade/QMT 完整版封闭不可集成(详见 [[khquant-analysis]] 同源调研)。
---
## 2. 总体架构
```
[网络A · 局域网] [公网 VPS] [网络B · 异地]
43.133.235.218
NAS Docker ┌─ frps(:7000) Windows 机器
sanguo_vnpy_v2 ──HTTPS────────►│ Caddy(:443) ├ miniQMT 客户端(登录常驻)
live_orchestrator 下单/查询 │ bridge.mysanguo.top ├ bridge 服务(:8765) ← D期写
│ → 127.0.0.1:18765 │ ↓ xtquant 本地 IPC
└─ frps(:18765) ◄─frp隧道──── └ frpc(连 frps:7000
```
下单链路(6 跳):
`sanguo(NAS) → 公网 → Caddy(VPS:443) → frps(18765) → frp隧道 → Windows frpc → bridge(:8765) → xtquant → miniQMT`
日线级单 bar 推进,延迟完全无感;高频不适用(非本项目场景)。
---
## 3. 网络层(已完成 ✅)
| 组件 | 配置 | 状态 |
|------|------|------|
| Windows frpc | `frp v0.69.1``frpc.toml`serverAddr 43.133.235.218:7000 + token + qmt-bridge proxy 8765→18765| ✅ 已连(VPS 18765 监听确认)|
| frpsVPS| 无 allowPorts 限制 | ✅ |
| CaddyVPS| `bridge.mysanguo.top { reverse_proxy 127.0.0.1:18765 }` | ✅ validate + reload |
| DNSNameSilo| `bridge A 43.133.235.218` TTL 3600 | ✅ 生效 |
| HTTPS 证书 | Caddy 自动 ACMETLS1.3| ✅ |
| 全链路验证 | `curl https://bridge.mysanguo.top``502 server: Caddy` | ✅ 502=隧道通到 Windows8765 待写)|
Windows frpc 开机自启:任务计划程序(`sanguo-frpc`,onstart + 失败重启)或启动文件夹,见 NAS `/volume1/stock/frp_windows/README.md`
---
## 4. bridge 服务设计(Windows 端,D-1 待开发)
### 4.1 形态
- **FastAPI** HTTP 服务,监听 `127.0.0.1:8765`(仅本地,frpc 转发外部流量)
- 启动时初始化 `xtquant.XtQuantTrader`(连本地 miniQMT 客户端)+ `xtdata`(行情)
- 自启:任务计划程序(`sanguo-bridge`onstart,依赖 miniQMT 客户端已登录)
### 4.2 接口(最小集,YAGNI
| 方法 | 路径 | 入参 | 返回 | 说明 |
|------|------|------|------|------|
| GET | `/health` | — | `{status, miniqmt_connected}` | 健康检查(frpc/Caddy 探活)|
| POST | `/order` | `{code, action:buy/sell, price, volume, reason}` | `{order_id, ok}` | 下单(`xt_trader.order_stock`|
| POST | `/cancel` | `{order_id}` | `{ok}` | 撤单 |
| GET | `/account` | — | `{cash, frozen, market_value, total}` | 资金(`xt_trader.query_stock_asset`|
| GET | `/positions` | — | `[{code, volume, can_use, avg_price, ...}]` | 持仓(`xt_trader.query_stock_positions`|
| GET | `/trades` | `?since=<ts>` | `[{code, action, price, volume, time}]` | 成交回报(账本同步用)|
> 股票代码格式:xtquant 用 `600000.SH` / `000001.SZ`sanguo 内部 `sh600000`bridge 做转换)。
### 4.3 xtquant 调用要点(参考 OSkhQuant 架构,不抄代码)
- `xt_trader = XtQuantTrader(path, session_id)``xt_trader.start()``connect()``subscribe(account)`
- 下单:`xt_trader.order_stock(account, code, order_type, volume, price_type, price, strategy_name, order_remark)`
- `price_type`:限价 `XT_PRICE_LIMITED` / 市价 `XT_PRICE_LATEST_PRICE`
- A 股 T+1`query_stock_positions``can_use_volume` 即可卖量(buy 当日计 frozen
- 行情:`xtdata.download_history_data` + `get_market_data_ex`(实盘 step 用实时,非历史)
- 回调:`xt_trader.register_callback` 异步接收成交通知
---
## 5. sanguo 端改造(D-3 待开发)
### 5.1 配置(config/data_platform.yaml 加)
```yaml
live:
bridge_url: https://bridge.mysanguo.top
bridge_token: ${BRIDGE_TOKEN} # 环境变量,不进 git
enabled: false # 总开关,模拟联调时再开
```
### 5.2 live_orchestrator 改造(`sanguo_trader/live_orchestrator.py`
现状:`live_step` 恢复状态 → warmup → 当日 bar → `engine.step` → 存状态。`step` 返回 `(pending_new, closes)`
D 期加「实盘执行分支」:当 `account.mode == 'live'``live.enabled`
1. `step` 产生的**当日成交**`closes`)→ 同步 POST `/order` 到 bridge(真实下单到 miniQMT
2. 次日开盘前,从 bridge `GET /positions` `/account` 拉真实持仓/资金,**校正** account 账本(真实回报为准,纠模拟撮合漂移)
3. 鉴权:每个请求带 `X-Bridge-Token` header
### 5.3 模拟撮合 vs 实盘下单的关系(关键设计决策)
| 模式 | 说明 | D 期采用 |
|------|------|---------|
| **A 影子下单**(推荐先)| PaperEngine 照常模拟撮合(账本准),同时把信号 POST bridge「影子」下单到 miniQMT 模拟环境,**对比两者**验证一致性 | ✅ 联调期 |
| **B 实盘驱动** | 真实下单 + 成交回报驱动账本,PaperEngine 退化为信号生成器 | 切实盘后 |
→ 联调先用 A(模拟盘端到端,零资金风险),一致性验证后切实盘切 B。
---
## 6. 鉴权与安全(⚠️ bridge.mysanguo.top 已公网暴露)
**实测**:域名一上线即被扫描器(`81.171.74.60` 等)打 `/dump.sql` `/wp-config.php` `/secrets.json`。必须:
1. **共享密钥**:每个请求 header `X-Bridge-Token: <random>`bridge 校验,不符 401。token 走环境变量(sanguo + Windows bridge 两端同值),**不进 git**
2. **最小接口**:只放 §4.2 的接口,不暴露 xtquant 全能力
3. **限速**FastAPI middleware 限流(防爆破)
4. **可选 IP 白名单**sanguo 经 VPS 反代,bridge 看到的源 IP 是 VPS43.133.235.218)→ bridge 可加白名单只接受 frps 来源
5. **审计日志**bridge 记录每笔下单(code/action/volume/price/来源 IP/时间),便于复盘异常
---
## 7. 端到端联调方案(模拟盘先行)
| 阶段 | 环境 | 资金风险 | 目标 |
|------|------|---------|------|
| D-4a | miniQMT **模拟客户端**(现已在跑)| 零 | bridge 端到端打通:sanguo 信号 → bridge → miniQMT 模拟下单 → 回报 |
| D-4b | 模拟客户端 + **影子对比** | 零 | PaperEngine 模拟撮合 vs bridge 真实下单,验证一致性(成交价/持仓/资金)|
| D-4c | **小资金实盘**(切实盘账户)| 低 | 真金白银小单验证,切换模式 B |
| D-4d | 正式实盘 | 正常 | 纳入每日 20:30 scheduler |
---
## 8. 任务拆分(D 期工作清单)
| 编号 | 任务 | 端 | 状态 |
|------|------|-----|------|
| D-1 | bridge MVPhealth/order/account/positions + 鉴权)| Windows | ✅ 代码 `eff9ed2` + 公网实测(health/account/positions/order 端到端 200|
| D-2 | bridge 自启 + frpc 自启 + 稳定性 + 半自动更新 | Windows | ✅ 自启(启动文件夹)+ bridge 完善 `cadc59e`(自动重连 miniQMT + /health 真实探活 + 交易日判断)+ 半自动更新(`update.bat` `b25b1e0` + sparse clone,见 windows-bridge-setup.md `8f51b02`/`aef4612`|
| D-3 | sanguo 影子下单分支(bridge_client + 幂等)| NAS | ✅ 代码 `ff84b3d` + 持久测试 11 + mock bridge 4`38f5635`/`2393097`|
| D-4a | 端到端影子下单(真 bridge)| 两端 | ✅ 注入成交 → 自动影子 → 真 bridge → miniQMT 报单 order_id 1090519054/1090519055 + 幂等验证 |
| D-4b | 模拟撮合 vs 实盘成交价一致性 | 两端 | ⏳ 周一交易日(5 次试单确认 miniQMT `[120141][证券交易未初始化]`:交易日才初始化交易通道 + 行情站点周末关 → 无法成交,等周一)|
| D-4c | 模式 Bbridge 回报驱动账本)| 两端 | ✅ 代码 `e77c9df` + test_reconcile 10 + 真桥验证(reconcile 读 bridge → 校正 account 1000万/空 + 持久化)|
| D-5 | 文档/验收/部署 | — | ✅ 设计 §8 + Windows 部署清单 + bridge 部署/半自动更新(windows-bridge-setup.md+ Issue #4 进度(8 条 comment|
> **验证总账**(不依赖周一的,全过):D-1 公网实测 / D-3 持久测试 + NAS 环境 108 passed / D-4a 端到端影子(真 bridge order_id/ D-4c 模式 B reconcile(真桥账本校正)/ D-2 bridge 完善(探活 + 容错在 miniQMT 行情关场景验证生效)/ D-5 文档。
> **D-4b 等周一**miniQMT 行情站点开 + 交易日初始化(120141 消失)→ scheduler 20:30 触发 live_step(开 enabled + mode_b + token),策略信号 → 模拟撮合 + bridge 真实成交 → 对比 paper_trades.price vs bridge /positions avg_price。
### 运维发现(D 期联调实测,Issue #4 comment #1127/#1128
1. **miniQMT `[120141][证券交易未初始化]`**:miniQMT 证券交易初始化**只在交易日做**(init_date 同步当日)。非交易日(周末/节假日)+ 行情站点关 → 报单必 120141。scheduler 应只在交易日 20:30 触发实盘下单。
2. **miniQMT 行情站点周末维护关闭**:周末 bridge 连不上 miniQMT`miniqmt_connected:false`)。/health 真实探活如实反映(验证 D-2 探活生效,旧版会假阳性 true)。
3. **bridge 不自动重连 miniQMT**(已修复 `cadc59e`):miniQMT 重启后旧连接失效,新版 `_retry_with_reconnect` 自动重连重试。
4. **token 分离(⚠️ 切实盘前必办)**:当前 gitea access token 混做 BRIDGE_TOKEN(测试阶段图省事)。bridge.mysanguo.top 公网每请求传 token,暴露面 > gitea token 只在本地 clone URL。**切实盘前分离**BRIDGE_TOKEN 用独立 `secrets.token_urlsafe(32)`gitea token 只 clone。
---
## 9. 风险与兜底
| 风险 | 影响 | 兜底 |
|------|------|------|
| Windows/miniQMT/frpc/bridge 四常驻,任一断 | 下单链路断 | 日线级 → 「断线次日补」+ bridge `/health` 探活 + scheduler 重试 |
| VPS 单点 | 全链路断 | 接受(日线级);备选 Tailscale 直连绕 VPS |
| bridge token 泄露 | 任意人可下单 | 环境变量 + 不 commit + 审计日志 + 限速 |
| miniQMT 停新申请(2026/7/6)| 新账户无法开 | 老账户可用;新账户换其他提供 miniQMT 券商(华泰/中泰/国信)|
| 模拟撮合与实盘成交价漂移 | 账本不准 | 模式 B 以 bridge 回报为准校正 |
| 公网扫描/攻击 | bridge 被打 | §6 鉴权 + 最小接口 + 限速 |
---
## 10. 相关
- 源码参考:`/volume1/KnowledgeBase/github-repos/OSkhQuant`xtquant 调用链路,CC BY-NC 仅参考架构)
- [[khquant-analysis]] wiki
- [[vps-deployment]] wikiFRP/Caddy 基建)
- vps-access skill
- 前序:`docs/superpowers/specs/2026-07-07-phase3c-paper-trading-design.md`
- 网络层落地:NAS `/volume1/stock/frp_windows/`frpc + README