docs(phase2): 因子/回测层 design(brainstorming 3 轮确认,待 review)
This commit is contained in:
@@ -0,0 +1,235 @@
|
||||
# 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(不用 Celery,ADR-2)
|
||||
- 不引 Qlib(用 vnpy.alpha,ADR-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 弱 CPU(braswell 2 核)海量回测慢 | 中 | S2 评估 max_workers,接口预留 Ray 分布式(Phase 3+) |
|
||||
| peewee 冲突阻塞 Alphalens | 中 | S3 前置解决 |
|
||||
| BacktestingEngine headless 调用坑(fork/Qt) | 低 | Phase 1 已验证 Python 3.14 + vnpy 4.4.0 不拉 Qt;S2 复验 |
|
||||
|
||||
---
|
||||
|
||||
## 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 |
|
||||
Reference in New Issue
Block a user