Files
sanguo_vnpy_v2/docs/superpowers/specs/2026-07-05-phase2-factor-backtest-design.md
T

236 lines
11 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 2 因子/回测层 Design(架构设计)
> **对应 PRD**`docs/superpowers/specs/2026-07-05-vnpy-quant-platform-prd.md`
> **承接**Phase 1 数据层(已 DONE,见 `docs/superpowers/reports/2026-07-05-phase1-data-layer-completion.md`
> **范围**:因子层 + CTA 回测层 + 任务编排 + 轻量 FastAPI
> **日期**2026-07-05
> **状态**Draft(待用户 review
---
## 0. 范围决策(brainstorming 已确认)
| 决策点 | 选择 | 理由 |
|--------|------|------|
| Phase 2 范围 | 因子层 + CTA 回测层 + 任务编排 + 轻量 FastAPI(完整闭环) | 用户要"因子+回测全做" |
| 回测范式 | 因子分层回测 + CTA 策略回测两条都要 | 覆盖多因子研究 + 策略回测两个闭环 |
| 编排边界 | 含轻量 FastAPI(提交/查询,无 JWT/WS/前端) | 计算层稳了再套完整 Web(Phase 3 |
| 代码组织 | 方案 A 分层解耦(4 包) | 单一职责、独立可测、vnpy 零改造 |
---
## 1. 架构总览
```
┌──────────────────────────────────────────────┐
│ sanguo_api (轻量 FastAPI) │
│ POST /backtest/cta · /optimize · /factor │
│ GET /task/{id} · /task/{id}/result │
└──────────────┬───────────────────────────────┘
│ submit_task
┌──────────────┴───────────────────────────────┐
│ sanguo_orchestrator (编排层) │
│ multiprocessing pool · 任务状态机 · runner │
└──────┬───────────────────────────┬───────────┘
│ │
┌──────┴────────────┐ ┌──────────┴────────────┐
│ sanguo_factor │ │ sanguo_backtest │
│ vnpy.alpha 适配 │ │ BacktestingEngine │
│ 因子注册(可插拔) │ │ run_optimization │
│ Alphalens 分析 │ │ result_store │
└──────┬────────────┘ └──────────┬────────────┘
│ │
└───────────┬───────────────┘
│ read_db_daily / read_parquet_daily
┌──────────────────┴───────────────────────────┐
│ Phase 1 数据层(已 DONE
└──────────────────────────────────────────────┘
```
**核心原则**(继承自 PRD/design):
- vnpy 引擎层零改造(ADR-3),适配层只包装
- 因子层可插拔(ADR-8
- 多进程 + Ray(不用 CeleryADR-2
- 不引 Qlib(用 vnpy.alphaADR-1
**两条回测路径物理隔离**
- 因子分层回测 → `sanguo_factor.analyzer`Alphalens IC/IR/分层收益)
- CTA 策略回测 → `sanguo_backtest.cta_engine`BacktestingEngine 时间序列)
---
## 2. 组件设计
### 2.1 `sanguo_factor/`(因子层)
| 模块 | 职责 | 关键接口 |
|------|------|---------|
| `alpha_adapter.py` | vnpy.alpha 适配(DataProxy + cs_function 范式) | 内部,封装 vnpy.alpha 数据接入 |
| `registry.py` | 因子注册机制(`@register_factor` 装饰器,ADR-8 可插拔) | `register_factor(name, fn)` / `get_factor(name)` |
| `library.py` | Alpha158/101 内置因子 + 自定义因子统一注册 | `list_factors()` / `list_categories()` |
| `analyzer.py` | Alphalens 适配(IC/IR/分层回测),analyzer 接口可插拔 | `compute_factors(symbols, names, start, end) → DataFrame`<br>`analyze_factor(values, fwd_returns) → FactorReport` |
**因子注册范式**(遵循 vnpy.alpha):
```python
@register_factor("ma5", category="trend")
def ma5(proxy: DataProxy, symbol: str, dt: datetime) -> float:
# cs_function 范式
...
```
自定义因子按此接口注册,与 Alpha158/101 内置因子统一管理。
**扩展点**:analyzer 接口可插拔——未来加非 Alphalens 分析器不改架构。
### 2.2 `sanguo_backtest/`(回测层,CTA 路径)
| 模块 | 职责 | 关键接口 |
|------|------|---------|
| `cta_engine.py` | BacktestingEngine wrapper(单标的策略回测,headless | `run_cta_backtest(strategy, symbol, params, start, end) → BacktestResult` |
| `cta_optimizer.py` | run_optimization wrapper(参数网格,`max_workers``output=False` | `run_cta_optimization(strategy, symbol, grid, start, end) → list[OptResult]` |
| `result_store.py` | 结果存储:SQLite 统计 + parquet 净值/成交 | `save_result(result) → id` / `load_result(id)` / `list_results(filter)` |
**结果存储 schema**SQLite `backtest_stats` 表):
- 任务字段:`id, task_id, type(cta/optimize/factor), status, created_at`
- 策略字段:`strategy, symbol, params(json), start, end`
- 指标字段:`return, sharpe, max_drawdown, win_rate, ...`
- 文件指针:`equity_path(parquet), trades_path(parquet)`
- 错误信息:`error_msg(text, 任务 failed 时记录异常)`
> 净值曲线 + 成交明细不入库(大数据),存 parquet 文件,db 存路径指针。
**因子层范围边界**:本 design 因子层只到 **Alphalens 分层分析**(IC/IR/分层收益),**不含组合回测**(选股→加权→调仓的主动组合管理)。组合回测是更复杂的范式,留待未来 phase。
### 2.3 `sanguo_orchestrator/`(编排层)
| 模块 | 职责 |
|------|------|
| `pool.py` | multiprocessing pool(基于 S2 spike 结果定 max_workers 策略) |
| `task.py` | 任务状态机:`pending → running → done/failed` |
| `runner.py` | 调度器:分发 cta_backtest / cta_optimization / factor_analysis |
**接口**
- `submit_task(task_spec) → task_id`(异步,立即返回)
- `get_task_status(task_id) → TaskStatus`
- `get_task_result(task_id) → Result`
### 2.4 `sanguo_api/`(轻量 FastAPI
| 路由 | 功能 |
|------|------|
| `POST /api/v1/backtest/cta` | 提交 CTA 回测任务 |
| `POST /api/v1/backtest/optimize` | 提交参数优化任务 |
| `POST /api/v1/factor/analyze` | 提交因子分析任务 |
| `GET /api/v1/task/{id}` | 查询任务状态 |
| `GET /api/v1/task/{id}/result` | 获取任务结果 |
**不含**(留 Phase 3):JWT 认证、WS 进度推送、Vue 前端。
---
## 3. 数据流
```
因子分析闭环:
read_db_daily → compute_factors(多 symbol) → analyze_factor(Alphalens)
→ FactorReport(IC/IR/分层收益) → 报告文件(parquet + html)
CTA 回测闭环:
read_db_daily → BacktestingEngine(strategy, params)
→ 统计指标入 SQLite + 净值/成交入 parquet
参数优化闭环:
read_db_daily → run_optimization(grid, max_workers)
→ 多组结果入 SQLite + 最优组合标记
API 触发链:
FastAPI 收请求 → orchestrator.submit_task → pool 异步执行
→ 结果落库 → GET /task/{id} 轮询状态/结果
```
---
## 4. Spike 前置(Phase 2 第一步,落地前必做)
| 顺序 | Spike | 验证内容 | 风险 | Fail 的 fallback |
|------|-------|---------|------|-----------------|
| **S3 先** | peewee 版本冲突 | Alphalens(empyrical-reloaded 要 peewee<3.17.4) vs vnpy_sqlite(peewee 4.1.1) 能否共存 | 中 | alphalens-reloaded 替代 / venv 隔离 / 降级 peewee |
| **S1** | vnpy.alpha A 股支撑度 | T+1/100 股/涨跌停/停牌 在 alpha 模块的支撑度 | 中 | 自建轻量因子层(pandas + ta-lib |
| **S2** | run_optimization 多进程 | 容器内 `max_workers` 行为 + NAS 弱 CPU 资源占用 | 低 | 降级单进程 + 自建 pool |
**S3 最先**:依赖冲突不解决,Alphalens 装不上,S1 无法跑。
**S1 关键路径**:决定因子层方案 A 可行性,fail 则 fallback 自建因子层(影响范围限 `sanguo_factor`,不影响 `sanguo_backtest`)。
---
## 5. 错误处理
| 场景 | 策略 |
|------|------|
| 数据缺失 | 复用 Phase 1 `validator`,缺失数据任务直接 `failed` |
| 因子计算异常 | 单因子失败隔离(try/except + 记录),不影响其他因子 |
| 回测异常 | 捕获 → 任务状态 `failed` → 错误信息入 `backtest_stats.error_msg` |
| 多进程子进程崩溃 | 主进程感知(`Pool.apply_async` callback/errback)→ 任务标记 `failed` |
| API 参数非法 | Pydantic 校验 → 422 返回明确错误 |
---
## 6. 测试策略
| 类型 | 范围 | 工具 |
|------|------|------|
| 单元测试 | 每组件独立(mock vnpy 引擎、mock pool | pytest,复用 Phase 1 conftest |
| 集成测试 | 因子计算 + CTA 回测端到端(真实 vnpy,小数据集) | pytest + 真实 vnpy_v4.4.0 |
| Spike | S1/S2/S3 风险探测(非 pass/fail 测试,是验证 task | 独立 spike script |
| 覆盖率 | ≥ 80% | pytest-cov |
---
## 7. 关键风险
| 风险 | 等级 | 缓解 |
|------|------|------|
| vnpy.alpha 不支持 A 股特性 | 中 | S1 spike 前置,fail 则 `sanguo_factor` fallback 自建 |
| NAS 弱 CPUbraswell 2 核)海量回测慢 | 中 | S2 评估 max_workers,接口预留 Ray 分布式(Phase 3+ |
| peewee 冲突阻塞 Alphalens | 中 | S3 前置解决 |
| BacktestingEngine headless 调用坑(fork/Qt | 低 | Phase 1 已验证 Python 3.14 + vnpy 4.4.0 不拉 QtS2 复验 |
---
## 8. 与 PRD ADR 对应
| ADR | 本 design 落点 |
|-----|---------------|
| ADR-1 不引 Qlib(用 vnpy.alpha | §2.1 因子层基于 vnpy.alpha |
| ADR-2 multiprocessing + Ray(不用 Celery | §2.3 pool.py,§7 Ray 预留 |
| ADR-3 vnpy 引擎零改造 | §1 核心原则,§2 各 wrapper 只包装 |
| ADR-4 复用 v1 数据丢弃 v1 回测 | §3 数据流复用 Phase 1 接口 |
| ADR-8 因子层可插拔 | §2.1 registry.py + analyzer 接口 |
---
## 9. Phase 1 衔接
Phase 2 全部基于 Phase 1 提供的下游接口构建:
- `read_db_daily(symbol, start, end, cfg) → list[BarData]` — vnpy 原生 BarData,直接喂 vnpy.alpha / BacktestingEngine
- `read_parquet_daily(...)` — parquet 快速读取路径(因子批量计算用)
- `UpdateScheduler` — 数据增量更新(回测前确保数据新鲜)
---
## 10. 实施顺序(概要,详细 plan 由 writing-plans 出)
1. **Spike 前置**S3(peewee) → S1(vnpy.alpha A 股) → S2(run_optimization)
2. **因子层** `sanguo_factor`alpha_adapter + registry + library + analyzer
3. **回测层** `sanguo_backtest`cta_engine + cta_optimizer + result_store
4. **编排层** `sanguo_orchestrator`pool + task + runner
5. **API 层** `sanguo_api`5 路由 FastAPI
6. **集成 + 端到端冒烟**
---
## 变更记录
| 日期 | 变更 | 来源 |
|------|------|------|
| 2026-07-05 | 初稿,基于 brainstorming 3 轮决策 | superpowers brainstorming |