Files
sanguo_vnpy_v2/docs/design/paper-shadow-desk-design.md
T

158 lines
10 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.
# 模拟盘影子交易柜台设计 v2(验收第四轮 #4)
> 状态:设计稿 v2(2026-08-14,按用户反馈重写驱动方式)。**P0 对账已通过(2026-08-14);
> P1 影子柜台已上线(2026-08-14 晚,shadow#39 实跑)**;P3 前半(双轨对账报表)已实现(534a06a)。
> v1 的「schtask 每 15 分钟定时拉数据」已废弃——用户明确:数据要与实盘完全一样
> v1 的「schtask 每 15 分钟定时拉数据」已废弃——用户明确:数据要与实盘完全一样
> 由 miniQMT 实时提供,步长由策略自己的周期决定(tick 到月线),15 分钟只是举例。
## 0. 一句话版(业务视角)
在 VPS 上放一个「模拟券商」:
- **行情**:跟实盘完全一样,从 miniQMT 实时订阅(tick / 各周期 bar);
- **账户**:每个策略实例一个独立虚拟账户(资金、持仓、净值曲线各自独立,互不干扰);
- **交易**:策略下单不发给券商,由模拟券商在**下单那一刻的实时价 + 滑点**本地成交;
- **周期**:每个策略声明自己的周期(tick/1m/5m/15m/30m/d/月线合成),柜台按各自的周期喂数据。
跟实盘唯一的区别就是订单不出门。
## 1. 目标 / 非目标
**目标**
- 行情驱动 = 实盘同款:miniQMT(xtdata)实时推送,事件驱动,非定时轮询。
- 步长 = 策略自身周期(tick 到日线/月线合成),柜台不预设统一步长。
- 本地模拟撮合:实时价 + 滑点 + 真实费率(佣金/印花税/最低佣金)。
- 多策略多账户完全隔离:每实例独立虚拟账户,独立盈亏曲线。
- 状态可恢复:进程重启后从断点续跑(checkpoint),不丢已结算数据。
**非目标(MVP 不做)**
- 订单真发券商(这是后续真实现盘;本设计正是它的前置演练场)。
- 撮合排队/部分成交等微观结构(实时价全额成交,先验证策略行为)。
- CTA 个股策略接入(先组合策略;CTA 的 vnpy 线保持现状)。
## 2. 架构
```
VPS(miniQMT 客户端保持登录,唯一有实时行情的机器)
┌───────────────────────────────────────────────────────┐
│ sanguo-shadow-desk 常驻进程(交易时段运行,开机自启) │
│ ├─ 行情层:xtdata 订阅(tick 推送 + 各周期 bar 推送) │
│ │ 按每个策略实例声明的周期分发(月线=日线本地合成) │
│ ├─ 账户层:每实例一个虚拟账户(现金/持仓/净值独立) │
│ ├─ 撮合层:本地成交 = 下单时刻实时价 + 滑点 + 费率 │
│ │ (复用 sanguo_trader 费率/风控件,涨跌停/停牌拦截) │
│ ├─ 落库:成交/持仓/净值 → paper 库(VPS 本地) │
│ └─ checkpoint:每成交/每 bar 结算后记断点(重启恢复用) │
└───────────────────────────────────────────────────────┘
↓ 公网 webvnpy.mysanguo.online → VPS API
前端模拟盘页(现有,读库即得盘中实时刷新)
兜底:收盘后日终对账(VPS 晚间跑一次,发现盘中断档则用日终全量重放补齐
——沿用现有 portfolio_paper 能力;另保留 NAS 20:30 日终重放作交叉对照)
```
## 3. 关键设计决策
### 3.1 行情:订阅推送,不轮询
- xtdata `subscribe_quote`(单标的周期 bar/ `subscribe_whole_quote`(全市场 tick 快照)
都是**推送**语义,与实盘网关行为一致;断线自动重连。
- 策略周期映射:tick → tick 推送;1m/5m/15m/30m/d → 对应周期 bar 推送;
月线/周线 → 日线本地合成(与 vnpy BarGenerator 同思路)。
- 需要历史因子(动量等):直查 VPS 本地库(unified provider),与实时推送互补。
### 3.2 撮合:实时价成交(与实盘市价单最接近)
- 订单到达即以下单时刻实时价 + 滑点成交(替代回放模式的 NEXT_OPEN/CURRENT_CLOSE
——那是没有实时价时的近似;现在有实时价,直接用)。
- 涨跌停/停牌/未成交约束复用 `sanguo_trader/limit.py` 既有逻辑。
- 费率按账户行配置(佣金/印花税/最低佣金/滑点),与回测同口径。
### 3.3 恢复:checkpoint 增量(保留 v1 验证结论)
进程重启/断电后不从头跑:引擎原生支持初始持仓
`initial_positions=[{security, amount, avg_cost}]`+ 初始资金恢复,
策略因子历史直查本地库不受引擎窗口限制 → 从断点下一根 bar 续跑,
无双重成交。对账用例(P0)显式覆盖跨除权日的复权正确性。
### 3.4 策略状态约定
- 需要跨 bar 记忆的状态一律放持仓/账户(天然随 checkpoint 恢复);
- 策略内临时变量只放可重建的缓存(重启丢失不影响正确性)。
## 4. 存储变更(paper 库,向后兼容)
- `paper_accounts` + `engine` 列('eod_replay'NAS 现状)/ 'shadow'VPS 新),新账户默认 shadow)。
- checkpoint 扩展为 `checkpoint_dt`(最后已结算 bar 时间戳,tick/分钟精度)
+ `cash` + `positions_json` + `avg_cost`。旧日粒度行迁移:视作当日收盘。
- 成交/净值/持仓表结构不变(datetime 字段天然容纳 tick/分钟精度)。
## 5. 运行方式
- VPS schtask `sanguo-shadow-desk`:交易时段前启动常驻进程(BootTrigger +
交易日 09:15 拉起,15:30 后自动退出/空闲驻留皆可,首版选驻留+收盘结算)。
- 单实例文件锁(防双开重复撮合)。
- CLI 手工入口:`python -m sanguo_trader.shadow_desk [--account N]`(补跑/调试)。
- miniQMT 登录依赖:现有数据采集 schtask 同样依赖它,无新增要求,
但影子柜台进程在交易时段**不能容忍长时间掉线**——掉线期间不撮合,
重连后由日终对账补(见 §2 兜底)。
## 6. 分期
| 期 | 内容 | 验收 |
|----|------|------|
| P0 | 对账 spikecheckpoint 续跑 vs 全量重放,末持仓/净值一致(含跨除权用例) | ✅ **已通过(2026-08-14VPS 真数据)**all_weather 2024 全年(242 交易日)全量重放 vs 3 段续跑(5月初/9月初分段,跨多次除权),期末 9 只持仓逐只一致、现金 2,256.29/总值 1,335,875.29 相对偏差 <1e-6、净值曲线 <1e-6。脚本 `scripts/shadow_desk/spike_p0_checkpoint_replay.py`runner 通道 `--initial-positions`+`final_portfolio`1e7d696 |
| P1 | 影子柜台常驻进程:bar 级订阅(分钟/日线)+ 实时价撮合 + 虚拟账户 + 落库 | ✅ **已上线(2026-08-14 晚)**supervisor schtask 拉起 shadow 进程,shadow#39all_weather 影子)实跑;ShadowBroker 5 协议方法补齐、bullet_trade 两层实例锁(b27c3b4/e1cafac),四实例齐跑 live3/4/5+shadow39。涨跌停/停牌拒单 61cc01e |
| P2 | tick 推送接入(tick 级策略)+ 月线/周线合成 | tick 策略可跑(挂起:等双轨验证稳) |
| P3 | 日终对账自动化 + NAS 交叉对照;影子单同步 QMT(真实现盘前置) | 前半 ✅ **双轨对账报表(534a06a2026-08-15**reconcile 四指标+自动配对 live5↔shadow39+API/CLI/supervisor 日终兜底;后半(影子单同步 QMT)挂起 |
工程分期不影响使用语义:策略侧从第一天就按「声明周期」配置,
tick 级在 P2 放开。
## 7. 风险
- **盘中掉线/miniQMT 掉登录**:断档期间不撮合,日终对账补齐;连续多日异常告警。
- **跨除权 checkpoint**P0 对账显式覆盖。
- **tick 级数据量**:tick 只在内存消费,落库仍为成交/净值/bar 级快照,库不膨胀;
但全市场 tick 订阅的内存/CPU 峰值需 P2 实测(先单标的/小池子放开)。
- **多账户规模**:虚拟账户互相隔离,几十个实例同进程无压力;
策略数上百时再谈多进程分片。
## 8. 双轨一致性验证(影子柜台 vs 实盘模拟,用户需求 2026-08-14
用户将同策略/实例同时跑在实盘模拟(miniQMT 真实下单)与影子柜台,
要求设计验证方案使两边最终盈亏尽量一致。
**预期管理**:完全一致不可能(实盘排队/部分成交/行情抖动),目标是
**差异可解释且小于阈值**——该差异即策略从纸面到真实的真实滑点成本,
本身是影子柜台的核心产出之一。
### 8.1 一致性参数(影子侧照抄实盘)
| 参数 | 设定 | 作用 |
|------|------|------|
| 行情源 | 同一 miniQMT | 同 bar 同时刻触发 → 信号相同 |
| 佣金/印花税/最低佣金 | 券商真实费率 | 消除费用差 |
| 滑点 | 初始 0.001,实测标定(价差均值重标) | 弥补实时价 vs 排队成交价差 |
| 涨跌停/停牌 | 同规则拦截 | 影子不成交实盘成不了的单 |
| T+1 / 100 股整手 | 影子同样强制 | A 股真实约束对齐 |
### 8.2 日终对账报表(自动)
| 对比项 | 一致标准 | 不一致归因动作 |
|--------|---------|---------------|
| 成交笔数 | 完全相同 | 实盘漏单 → 影子补拦截规则 |
| 每笔成交价差 | 平均 <10bps | 稳定偏一侧 → 用差值均值重标滑点 |
| 收盘持仓 | 逐只股票+数量相同 | 分歧报警,逐笔追查 |
| 净值偏差 | 月累计 <0.5% | 超限 → 滑点/费用重新标定 |
### 8.3 操作流程
同一策略同参数双轨并跑 ≥20 交易日(覆盖 2~3 个调仓日);
前几天价差数据用于滑点标定,之后两边贴合度应收敛到阈值内。
对账报表落在 VPS,前端模拟盘页可查(后续可加独立"双轨对账"页)。
## 9. 关联
- memory: `project-live-arch-shadow-mode`(实盘=影子模式既定方向,本设计是其前置)、
`xtdata-as-live-source`xtdata 行情能力与坑 volume÷100)、
`paper-matching-mechanism`(旧回放撮合语义,本设计取代其实走部分)
- 现状代码:`sanguo_trader/portfolio_paper.py`(EOD 全量重放→降级为对账兜底)、
`sanguo_trader/scheduler.py`NAS 20:30 job)、`sanguo_trader/matcher.py``sanguo_trader/limit.py`