docs(design): 模拟盘影子交易柜台设计(验收四轮#4):checkpoint增量+VPS盘中15m schtask+自有撮合;可行性已验(引擎initial_positions+attribute_history直查源) [nas]
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
# 模拟盘影子交易柜台设计(验收第四轮 #4)
|
||||
|
||||
> 状态:设计稿(2026-08-14),未动工。用户拍板方向后按分期实施。
|
||||
> 背景:现有模拟盘「实走」= NAS 每晚 20:30 全量重放(`sanguo_trader/portfolio_paper.py`),
|
||||
> 每日一个 step。对 15m 策略逻辑上不成立(日内 16 根 bar 只走 1 根),用户要求重设计为
|
||||
> **影子交易柜台**:独立于 miniQMT 的自有撮合台 + 实际行情 + 多策略多账户互不干扰,
|
||||
> ≈ 多个独立账号的实盘模拟。
|
||||
|
||||
## 1. 目标 / 非目标
|
||||
|
||||
**目标**
|
||||
- 盘中按 bar 到达驱动推进(15m 策略盘中每 15 分钟一个 step),非每日一次。
|
||||
- 自有撮合(复用 `sanguo_trader/matcher.py` 的 match_session 语义:NEXT_OPEN / CURRENT_CLOSE),
|
||||
独立于 miniQMT——miniQMT 只在真实盘才用。
|
||||
- 多策略多账户完全隔离:每个 paper 账户独立 checkpoint / 独立推进 / 互不影响
|
||||
(`paper_accounts` 行级隔离已具备)。
|
||||
- 状态可恢复:进程重启 / 断电后从 checkpoint 续跑,不丢已结算 bar。
|
||||
|
||||
**非目标(MVP 不做)**
|
||||
- tick 级实时撮合(bar 级撮合足够验证策略行为;tick 是后续量级)。
|
||||
- 影子单同步真实 QMT 账户(真实现盘方向,见 `project-live-arch-shadow-mode`,本设计是其前置)。
|
||||
- CTA 个股策略接入(先组合策略;CTA 的 vnpy 线保持现状)。
|
||||
|
||||
## 2. 关键可行性结论(已验证,2026-08-14)
|
||||
|
||||
bullet_trade 0.9.2 `BacktestEngine` 原生支持增量恢复所需的全部要素:
|
||||
|
||||
| 要素 | 引擎能力 | 用途 |
|
||||
|------|---------|------|
|
||||
| 持仓恢复 | 构造参数 `initial_positions=[{security, amount, avg_cost}]` | checkpoint 持仓续跑 |
|
||||
| 资金恢复 | 构造参数 `initial_cash` | checkpoint 现金续跑 |
|
||||
| 因子历史 | `attribute_history` **直查数据源**(count 回看至 current_dt,不受引擎 start_date 窗口限制,见 `bullet_trade/data/api.py:2569`) | 从 checkpoint+1bar 起跑无需暖机窗口,动量等因子历史完整 |
|
||||
| 撮合 | match_session 语义(回放逐 bar 撮合已是引擎行为) | 影子柜台撮合即「引擎撮合 + 我们的费率」 |
|
||||
|
||||
→ **增量 step = 每次新建引擎,start=checkpoint 下一根 bar,end=当前时刻,
|
||||
initial_cash/initial_positions=checkpoint 快照**。不需要给引擎打补丁,
|
||||
不需要暖机窗口(不会重放旧调仓 → 不会双重成交)。
|
||||
|
||||
## 3. 架构
|
||||
|
||||
```
|
||||
VPS(唯一有盘中实时数据的机器,xtdata T+0)
|
||||
┌────────────────────────────────────────────────────┐
|
||||
│ schtask sanguo-shadow-step(交易日 09:45–15:15 每 15m)│
|
||||
│ ↓ 触发 │
|
||||
│ sanguo_trader/shadow_desk.py step 全部 running 账户 │
|
||||
│ ├─ xtdata 拉自 checkpoint 起的新 15m/日线 bar │
|
||||
│ ├─ 每账户: BacktestEngine(checkpoint 续跑, ≤新bar) │
|
||||
│ │ initial_positions/cash ← paper_checkpoint │
|
||||
│ ├─ 新成交/持仓/净值 → paper 库(VPS 本地) │
|
||||
│ └─ update checkpoint_date │
|
||||
└────────────────────────────────────────────────────┘
|
||||
↓ 公网 web(vnpy.mysanguo.online → VPS API)
|
||||
前端模拟盘页(现有,读库即得盘中刷新)
|
||||
|
||||
NAS:保留现有 20:30 日终全量重放(互为对照;日线账户仍可走 NAS)
|
||||
```
|
||||
|
||||
**双轨说明**:同一账户只归一个引擎推进(按 `paper_accounts.engine` 列区分
|
||||
`eod_replay`(NAS 现状)/ `shadow`(VPS 新)),避免两边都写净值。
|
||||
|
||||
## 4. 数据细节
|
||||
|
||||
- **行情源**:xtdata(VPS 本地,T+0 当天 bar;日线 + 15m 全周期,见
|
||||
`xtdata-as-live-source`)。价格与 dbbardata 零漂移已验证;坑:volume ÷100。
|
||||
- **因子历史**:unified provider 读 VPS 本地库(`vps-local-data-layout`)。
|
||||
- **step 频率**:账户 interval=15m → 每 15 分钟;interval=d → 收盘后一次
|
||||
(15:15 那次统一结算当日)。非交易日 / xtdata 无新 bar → 幂等跳过(沿用
|
||||
现有 `already stepped` 语义,粒度从「日」变「bar 时间戳」)。
|
||||
|
||||
## 5. 存储变更(paper 库,向后兼容)
|
||||
|
||||
- `paper_accounts` + `engine` TEXT DEFAULT 'eod_replay'(新账户默认 'shadow')。
|
||||
- `paper_checkpoint`(或复用现有 checkpoint 字段)扩展为:
|
||||
`checkpoint_dt`(最后一根已结算 bar 的完整时间戳,15m 精度)+
|
||||
`cash` + `positions_json` + `avg_cost`(initial_positions 重建用)。
|
||||
现有行级 `checkpoint_date`(日粒度)迁移:首步把日粒度视作当日 15:00。
|
||||
- 成交/净值/持仓表不变(datetime 已含时间,15m 粒度天然兼容)。
|
||||
|
||||
## 6. 调度
|
||||
|
||||
- VPS schtask `sanguo-shadow-step`:交易日 09:45/10:00/…/15:15 每 15 分钟
|
||||
(.bat 自愈模板沿用 `schtasks-system-bat-gotchas` 经验:timeout 失效用 ping、
|
||||
断点续传、故障不阻塞下一轮)。
|
||||
- 幂等 + 单实例锁(文件锁,防上一轮 2-3 分钟未跑完时下一轮叠加)。
|
||||
- step 入口同时暴露 CLI(`python -m sanguo_trader.shadow_desk --account N`)便于手工补跑。
|
||||
|
||||
## 7. 分期
|
||||
|
||||
| 期 | 内容 | 验收 |
|
||||
|----|------|------|
|
||||
| P0 | spike:checkpoint 续跑与全量重放对账——同账户同区间,「全量一次跑」vs「分 3 段 checkpoint 续跑」末持仓/净值一致(容差 1e-6) | 对账脚本绿 |
|
||||
| P1 | shadow_desk.py step + engine 列 + checkpoint 扩展 + VPS schtask;日线账户先上(step=收盘一次,行为与现状等价但引擎换增量) | VPS 盘后 step 落库,前端可见 |
|
||||
| P2 | 15m 账户盘中每 15m step;前端模拟盘页盘中自动刷新 | 盘中实时性验收 |
|
||||
| P3(可选) | NAS EOD 重放降级为对账兜底;影子单同步 QMT(真实现盘前置) | — |
|
||||
|
||||
## 8. 风险
|
||||
|
||||
- **xtdata 未起 / 盘中缺 bar**:幂等跳过 + 下轮补(bar 缺口 ≤ schtask 间隔时
|
||||
一次补齐;断档大时告警人工触发全量对账)。
|
||||
- **分红/拆分跨越 checkpoint**:引擎 `_processed_dividend_keys` 按次重放,
|
||||
增量段跨除权日的复权处理需 P0 对账用例显式覆盖(构造跨除权区间)。
|
||||
- **策略内全局状态**(g. 变量跨 bar 累积):increment 段内有效,跨 checkpoint 丢失
|
||||
→ 约定策略把需持久化的状态写 context.portfolio(持仓即状态),g. 只放可重建缓存。
|
||||
- **费用口径**:沿用账户行费率(commission/stamp_duty/min_commission/slippage),
|
||||
与回测一致。
|
||||
|
||||
## 9. 关联
|
||||
|
||||
- memory: `paper-matching-mechanism`(撮合语义)、`project-live-arch-shadow-mode`
|
||||
(实盘=影子模式既定方向)、`xtdata-as-live-source`(VPS 数据源)
|
||||
- 现状代码:`sanguo_trader/portfolio_paper.py`(EOD 全量重放)、
|
||||
`sanguo_trader/scheduler.py`(NAS 20:30 job)、`sanguo_trader/matcher.py`
|
||||
Reference in New Issue
Block a user