投资策略调优与回测平台 — 设计文档 (SPEC)

版本: v1.0 · 日期: 2026-08-18 · 状态: 待审阅


1. 项目概述

一个代码驱动的量化策略调优与回测平台。策略以 Python 代码编写(非配置、非 DSL),支持多维度绩效评估、贝叶斯/网格/随机参数调优、walk-forward 滚动样本外验证、参数稳健性分析,并生成基于 ECharts 的独立 HTML 在线报告。

项目位置: ~/.hermes/workspace/quantlab 运行时: Python 3.12 (系统)

1.1 核心原则

  1. 代码优先: 策略 = Python 类,逻辑完全自由;参数通过声明式元数据暴露给调优器
  2. 禁止估算: 所有数据必须是真实来源(东方财富 / 中证指数官网)。任何缺失数据 → 明确报错并标注,绝不虚构、不估算、不插值伪造
  3. 无未来函数: 信号于 T 日收盘产生,一律 T+1 开盘价成交
  4. 可信回测: 调优结果必须经过 walk-forward 样本外验证 + 参数稳健性检验,报告给出完整证据链
  5. 可扩展: 回测内核为纯函数(数据+参数 → 结果),报告层完全独立,未来加 FastAPI + 任务队列即升级为交互式 Web 应用(B 型),内核零改动

1.2 非目标(v1 不做)


2. 需求与决策记录(已与用户确认)

决策项 结论
数据源 东方财富 API 为主源;中证红利全收益(H00922)东财无收录 → 中证指数官网补源
缓存 必须缓存,回测只读本地;东财有请求频率限制
策略编写 Python 代码,非配置非 DSL
信号频率 可配置,默认日频,不支持小时/分钟级
成交时点 次日开盘成交(无未来函数)
T+1 规则 不建模(中长期低频策略,影响可忽略)
交易载体 指数做信号与净值(方案 C);成本按 ETF 真实费率估算
分红处理 全部真实数据:创业板侧用 399606 创业板R(东财),红利侧用 H00922 中证红利全收益(中证官网)
初始持仓 100% 现金
基准 多基准支持;本策略: 100%创业板 / 50%+50% / 100%红利
评估指标 全套(见 §7)+ 任意时点买入持有 1/3/5 年盈利概率
无风险利率 当年活期存款利率,按年度计算(内置历史利率表,可编辑)
目标函数 默认: 夏普 − λ_mdd·max(0, MDD−0.20) − λ_turnover·年换手率;用户可写自定义 Python 目标函数;λ 可配 + 内置 λ 敏感性分析
调优方法 optuna (TPE 贝叶斯),网格/随机可切换;SQLite 持久化 → 断点续跑 + 进度展示
过拟合控制 walk-forward 滚动优化:默认 3 年优化 → 1 年实盘 → 逐年滚动 → 拼接 OOS 绩效(窗口可配)
稳健性 一维敏感性曲线 / 二维热力图 / ±10% 邻域统计+稳健性得分 / 参数漂移轨迹
报告 独立 HTML + ECharts(本地嵌入,jinja2 模板);preview-url 预览,不配 nginx
ETF 重叠期实证 2019-12 至今用真实 ETF 价格(515080/159915)复跑策略,与指数回测并排对比
项目位置 ~/.hermes/workspace/quantlab

3. 总体架构

quantlab/
├── SPEC.md
├── pyproject.toml            # 项目配置与依赖
├── README.md
├── quantlab/
│   ├── __init__.py
│   ├── data/                 # 数据层
│   │   ├── providers.py      # 数据源适配器(东财/中证官网)
│   │   ├── cache.py          # parquet 缓存管理 + 增量更新
│   │   ├── loader.py         # 统一加载接口 + 数据体检
│   │   └── instruments.py    # 资产注册表(代码/名称/来源/用途)
│   ├── engine/               # 回测引擎
│   │   ├── core.py           # bar 循环(事件驱动)
│   │   ├── portfolio.py      # 账户、订单执行、成本模型
│   │   └── models.py         # Trade / EquityCurve / PositionSnapshot
│   ├── strategies/           # ★ 策略代码区
│   │   ├── base.py           # Strategy 基类 + tunable_params 协议
│   │   └── ratio_rotation.py # 创业板/红利比值轮动策略(第一个策略)
│   ├── metrics/              # 评估指标
│   │   ├── returns.py        # 收益/年化/波动率/夏普
│   │   ├── risk.py           # MDD/回撤持续/Calmar/Sortino
│   │   ├── stats.py          # 胜率/盈亏比/月度胜率/滚动收益/换手
│   │   └── probability.py    # 任意时点买入持有盈利概率
│   ├── optimization/         # 调优层
│   │   ├── search.py         # optuna 封装(grid/random/tpe)
│   │   ├── objective.py      # 目标函数工厂(默认+自定义)
│   │   ├── walkforward.py    # walk-forward 滚动框架
│   │   └── robustness.py     # 稳健性分析
│   ├── report/               # 报告层
│   │   ├── generate.py       # 报告编排(数据 → HTML)
│   │   ├── charts.py         # ECharts 图表数据构建
│   │   └── templates/        # jinja2 模板 + 静态资源
│   ├── cli.py                # 命令行入口
│   └── config.py             # 全局配置(费率/窗口/λ 默认值)
├── tests/                    # pytest 测试
└── data/                     # 运行期数据(缓存 parquet、optuna db)【不入库】

扩展路径 (B 型应用): engine/metrics/optimization 全部是纯 Python 函数(无 IO 副作用),report 与核心解耦 → 未来 FastAPI 暴露 POST /backtestPOST /optimize + 任务队列即可,核心零改动。


4. 数据层

4.1 资产注册表 (instruments.py)

code 名称 类型 来源 用途
399006 创业板指 价格指数 东财 (secid=0.399006) 信号 X 分子
000922 中证红利 价格指数 东财 (secid=1.000922) 信号 X 分母
399606 创业板R 全收益指数 东财 (secid=0.399606) 创业板侧净值
H00922 中证红利全收益 全收益指数 中证官网 (perf/index-perf) 红利侧净值
159915 创业板ETF ETF 东财 (secid=0.159915) ETF 重叠期实证
515080 中证红利ETF ETF 东财 (secid=1.515080) ETF 重叠期实证

4.2 数据源适配器 (providers.py)

统一接口 fetch_daily(code, start, end) -> DataFrame[date, open, high, low, close, volume, amount]

4.3 缓存与更新 (cache.py / loader.py)

4.4 无风险利率


5. 策略层

5.1 Strategy 基类协议 (base.py)

class Strategy:
    name: str = "strategy"                    # 唯一标识
    tunable_params: dict[str, ParamSpec] = {} # 声明可调优参数(default/min/max/step/choices)
    # 生命周期钩子(引擎调用):
    def on_start(self, ctx): ...              # 回测开始(读取初始现金、注册资产)
    def on_bar(self, ctx): ...                # 每个交易日收盘后调用
    def on_end(self, ctx): ...                # 回测结束

5.2 第一个策略: 创业板/红利比值轮动 (ratio_rotation.py)

信号: X = close(399006) / close(000922)

参数 默认 范围 语义
L 0.40 [0.20, 0.80] X < L → 分批卖出红利、买入创业板
U 0.60 [0.40, 1.00] X > U → 分批卖出创业板、买入红利
n_batches 3 [1, 10] int 每轮换仓批次数
batch_interval 5 [1, 60] int 节拍器: 交易日间隔(天)
x_step 0.05 [0.01, 0.30] 节拍器: X 变动幅度触发
abort_mode "pause" ["pause","abandon"] 中途反悔: pause=条件保持暂停 / abandon=放弃本轮
batch_weight "equal" ["equal","front","back"] 批次权重: 等分/前重后轻/前轻后重(front=先买多, back=先买少)

节拍器语义(混合): 触发后,下一批在 距离上一批 ≥ batch_interval 个交易日 且 X 较触发时再变动 ≥ x_step 时才执行;两条件满足其一即允许(可配 AND/OR,默认 OR)。 中途反悔: pause = 若 X 回到中性区 (L ≤ X ≤ U),暂停剩余批次,等 X 再次穿越阈值才恢复;abandon = 直接取消剩余批次。 初始持仓: 100% 现金(引擎启动时不自动建仓,策略 on_start 决定首仓;本策略在首次 X<L 时开始分批建仓,若从未触发则全程持币——报告需标注该情形)。


6. 回测引擎

6.1 执行语义 (core.py)

逐交易日 bar 循环,每日顺序: 1. 执行: 用今日开盘价成交昨日 on_bar 产生的挂单(订单在生成后下一 bar 开盘执行;若开盘价缺失 → 顺延至下一有数据的交易日) 2. 记账: 以今日收盘价 mark-to-market,记录净值与持仓快照 3. 信号: 调用策略 on_bar(基于今日收盘数据,产生明日订单)

6.2 成本模型 (portfolio.py)

6.3 输出


7. 评估指标层 (metrics/)

对 equity_curve 与基准曲线计算:

类别 指标
收益 总收益率、年化收益(CAGR)
风险 年化波动率、最大回撤(MDD)、MDD 发生区间、最长回撤持续时间、水下时间占比
风险调整 夏普(当年活期利率)、Sortino、Calmar
交易 年换手率、年交易次数、总交易次数、单边换仓次数
分布 月度胜率、盈亏比(平均盈/平均亏)、滚动 1 年收益分布(分位数)
概率 盈利概率: 净值曲线上任意交易日买入并持有 1/3/5 年的盈利比例(滚动窗口滑窗统计,需覆盖区间≥持有期)

多基准: 基准同为资产组合(100%创业板 / 50+50 静态 / 100%红利),以 total_return 计算基准净值曲线,同套指标并列输出,并计算超额收益(策略 − 各基准)。


8. 调优层

8.1 搜索 (search.py)

8.2 目标函数 (objective.py)

8.3 walk-forward (walkforward.py)

8.4 稳健性分析 (robustness.py)

见 §9。


9. 稳健性分析

以 walk-forward 最终选定的参数(或用户指定参数)为中心:

  1. 一维敏感性曲线: 固定其余参数为最优值,单参数在 [min,max] 扫描,输出目标函数/夏普/收益/MDD 曲线(每个可调优参数一张)
  2. 二维热力图: 任意两参数网格扫描,目标函数着色热力图 + 最优值标记(支持对数/线性色阶)
  3. 邻域统计: 最优参数 ±10% 邻域内全部组合的绩效分布(中位数/最差/最好)+ 稳健性得分 = 邻域内绩效 ≥ 最优绩效×95% 的组合占比
  4. 参数漂移轨迹: walk-forward 各年最优参数随时间变化曲线(判断参数稳定性、市场状态切换信号)

10. 报告层 (report/)

10.1 技术选型

10.2 报告结构

  1. 概览卡片: 核心指标摘要(收益/夏普/MDD/换手)+ 自动生成的策略点评
  2. 净值对比: 策略 vs 多基准(含对数轴切换)
  3. 回撤曲线: 水下面积图 + MDD 标注
  4. X 比值 + 买卖点: 双轴图(X 比值曲线 + L/U 阈值线 + 分批买卖点标注)
  5. 仓位堆叠图: 红利/创业板/现金占比变化
  6. 月度收益热力图: 日历热力图
  7. 滚动 1 年收益分布: 分位数区间图
  8. 盈利概率: 持有 1/3/5 年盈利概率(策略 vs 基准)
  9. 交易分析: 交易时间线、成本累计曲线
  10. 绩效指标总表: 策略 vs 各基准全套指标
  11. 数据体检: 各资产数据完整性、新鲜度、缺口
  12. 调优/稳健性(若执行): walk-forward 拼接曲线、逐年最优参数表、λ 敏感性、稳健性图组
  13. 附录: 参数、配置、运行日志

11. ETF 重叠期实证


12. 测试计划 (tests/)

模块 关键测试
data 东财/中证适配器字段解析;缓存幂等;增量合并去重;数据体检检出缺口/空值
engine 次日开盘成交语义(含开盘缺失顺延);成本计算(佣金最低5元/滑点);现金约束(不能超买);分批订单部分成交
metrics 指标数值正确性(与手工计算对照);盈利概率滑窗;基准净值计算
optimization 目标函数默认/自定义;λ 惩罚生效;walk-forward 窗口边界;断点续跑恢复
report 报告生成成功;图表数据 JSON 结构;无 JS 错误(浏览器冒烟)
strategy ratio_rotation 状态机: 触发/节拍器/中途反悔(pause/abandon)/批次权重 各分支

13. 里程碑

# 内容 验收标准
M1 数据层 6 个资产全部可缓存,体检通过,报告数据体检小节
M2 引擎+成本模型 单资产买入持有回测正确(与手工账对照)
M3 指标层 全套指标 + 盈利概率 + 多基准计算正确
M4 报告管道 第一份完整回测报告(净值/回撤/买卖点/指标表)可预览
M5 调优层 optuna 搜索 + walk-forward + 断点续跑 + 进度
M6 稳健性 + λ 敏感性 全部图组可生成
M7 ETF 重叠期实证 + 打磨 报告全功能,测试通过,README

14. 待验证项(实现期首日确认)

  1. 东财 kline 接口对 399606 的 fqt 参数行为(spike 已验证数据可用,确认无复权影响)
  2. 中证官网 perf 接口的限流/频率限制(spike 单次 1.66MB 正常,确认批量策略)
  3. 活期存款利率历史表的权威数值(央行基准,实现时核对)
  4. ECharts 本地文件大小与加载方式(~1MB,内联 vs 独立文件)