11 KiB
11 KiB
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) → DataFrameanalyze_factor(values, fwd_returns) → FactorReport |
因子注册范式(遵循 vnpy.alpha):
@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) → TaskStatusget_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 / BacktestingEngineread_parquet_daily(...)— parquet 快速读取路径(因子批量计算用)UpdateScheduler— 数据增量更新(回测前确保数据新鲜)
10. 实施顺序(概要,详细 plan 由 writing-plans 出)
- Spike 前置:S3(peewee) → S1(vnpy.alpha A 股) → S2(run_optimization)
- 因子层
sanguo_factor:alpha_adapter + registry + library + analyzer - 回测层
sanguo_backtest:cta_engine + cta_optimizer + result_store - 编排层
sanguo_orchestrator:pool + task + runner - API 层
sanguo_api:5 路由 FastAPI - 集成 + 端到端冒烟
变更记录
| 日期 | 变更 | 来源 |
|---|---|---|
| 2026-07-05 | 初稿,基于 brainstorming 3 轮决策 | superpowers brainstorming |