策略复盘
回测结束后用 qs.reports.html 一键产出完整绩效报告,把指标、净值、回撤、基准对比集中在一页,快速定位策略的收益来源与风险暴露。
官方 README 提供 metrics / plots / basic / full / html 五个入口,其中 metrics 与 plots 各含 basic / full 两档,展开为 7 种输出形态。
| 报告 | 方法 | 内容 | 适用场景 | 输出形态 |
|---|---|---|---|---|
| 基础指标 | qs.reports.metrics(mode='basic') | 核心收益/风险指标子集 | 快速扫一眼关键指标 | 指标表(精简) |
| 完整指标 | qs.reports.metrics(mode='full') | 全量绩效与风险指标 | 深度指标审查/审计 | 指标表(完整) |
| 基础绘图 | qs.reports.plots(mode='basic') | 核心绩效图(净值/回撤等) | 快速看图 | 图表(精简) |
| 完整绘图 | qs.reports.plots(mode='full') | 全量绩效图(含滚动/分布等) | 全面可视化分析 | 图表(完整) |
| 基础报告 | qs.reports.basic() | 基础指标 + 基础绘图 | 日常快速复盘 | 指标 + 图(精简组合) |
| 完整报告 | qs.reports.full() | 完整指标 + 完整绘图 | 全面绩效评估 | 指标 + 图(完整组合) |
| HTML 报告 | qs.reports.html(stock, benchmark) | 完整 HTML tearsheet 文件 | 汇报/存档/分享 | HTML 文件 |
1. 导入库:import quantstats as qs —— 确认已按安装页装好依赖(Python ≥3.10 与 pandas/numpy/scipy/matplotlib/seaborn/yfinance)。预期输出:无报错即导入成功。
2. 取收益序列:stock = qs.utils.download_returns('META') —— 返回 pandas Series 日收益序列;也可以传入自备序列(例如从 akshare/tushare 导出的 A股收益)。预期输出:索引为日期、值为日收益小数(如 0.0123)。
3. 先做一次体检:qs.stats.sharpe(stock) —— 出报告前先算一个指标,确认序列没有 NaN 或异常值。预期输出:一个浮点数;若是 NaN 或 inf,先回查数据,不要直接拿去出报告。
4. 生成 HTML 报告:qs.reports.html(stock, 'SPY') —— QuantStats 的 benchmark 参数可传 ticker 字符串或 pandas Series。预期输出:当前工作目录出现一份 HTML tearsheet 文件。
5. 打开核对:浏览器打开该 HTML,逐项确认指标总览、净值曲线、回撤、月度收益、基准对比五个区块都正常渲染,中文没有变成方块。
以下为 QuantStats 报告常见的内容组成,具体区块与顺序以官方生成的报告为准。
| 区块 | 说明 | 来源方法 |
|---|---|---|
| 指标总览 | 夏普/索提诺/最大回撤/波动率等关键指标一览 | stats 模块 |
| 净值曲线 | 策略(与基准)的累计净值走势 | plots.returns / snapshot |
| 回撤图 | 历史回撤区间与最大回撤位置 | plots.drawdown / drawdowns_periods |
| 月度收益 | 逐月收益热力或表格 | plots.monthly_heatmap / stats.monthly_returns |
| 滚动指标 | 滚动夏普/波动率,观察绩效稳定性 | plots.rolling_sharpe / rolling_volatility |
| 基准对比 | 策略与基准的相对表现(需传 benchmark) | benchmark 参数 / information_ratio |
| 年度收益 | 逐年收益对比,看是否只靠某一年贡献 | plots.yearly_returns / stats.returns |
| 收益分布 | 日收益分布形态,判断偏度与尾部 | plots.distribution / histogram |
| 回撤区间明细 | 历史上几段大回撤的起止与恢复时长 | plots.drawdowns_periods |
| benchmark 怎么传 | 报告里会多出什么 | 注意点 |
|---|---|---|
| 不传 benchmark | 只有策略自身的指标与图 | 无法判断收益来自市场 beta 还是策略本身 |
| 传 'SPY' 这类 ticker | 净值/回撤叠加曲线与相对绩效指标 | 需要能联网从 yfinance 取到基准数据 |
| 传 QQQ 或行业 ETF | 与成长风格基准的相对表现 | 基准与策略风格不匹配时会把风格收益误当 alpha |
| 传 pandas Series(自建指数) | 完全自控口径的相对对比(如A股自编等权指数) | 索引必须与策略收益序列对齐并同频 |
| 传「买入持有」另一条曲线 | 衡量择时/择股是否真的加分 | 两条曲线不要共享同一段收益,避免自比自 |
| 频率传错(月收益配日频基准) | 相对指标照样有数字,但不可解释 | 生成前先校两条序列的频率与起止日期一致 |
1. 控制输出路径:通过 savefig 或相关参数指定报告/图表的保存路径与文件名(具体参数名以官方实现为准)。预期输出:文件落到你指定的目录,而不是脚本所在目录。
2. 固定文件名规则:把日期写进文件名(如 quantstats_report_2026-10-09.html)。预期输出:目录里按时间顺序自然排开,回溯时不必逐个打开。
3. TeX 输出:官方 README 提及 HTML 与 TeX 两类报告相关能力,如需 LaTeX 嵌入可用对应入口(以官方文档为准)。预期输出:得到可嵌入排版流程的源文件,而不是网页。
4. 转 PDF 存档:HTML 报告是自包含文件,在浏览器里打印为 PDF 即可。预期输出:一份不依赖网络、可长期留存的 PDF。
5. 分享前自检:换一台机器/换浏览器打开一次,确认没有外部依赖缺失、中文不乱码。预期输出:对方打开看到的内容与你本机一致。
回测结束后用 qs.reports.html 一键产出完整绩效报告,把指标、净值、回撤、基准对比集中在一页,快速定位策略的收益来源与风险暴露。
向客户或团队汇报组合绩效时,直接给出一份带基准对比的 HTML 报告,比散落的数字表格更直观、更易留存。
把绩效指标与图表打包成自包含 HTML 文件存档,便于事后追溯某段时间的策略表现与当时的基准对比。留存时连同当次原始收益序列一起归档,日后才能复现同一份结论。
下面这些是生成 HTML 报告时最容易卡住的地方,按「现象 → 原因 → 处置」逐条对照,比反复重装依赖省时间。
| 现象 | 常见原因 | 怎么处置 |
|---|---|---|
| 报告文件特别大、浏览器打开很卡 | HTML tearsheet 把每张图都内嵌进同一个文件,图越多体积越大 | 日常复盘改用精简入口(qs.reports.basic()),完整报告只在汇报/存档时需要时生成 |
| 图里的中文变成方块或乱码 | matplotlib 默认字体不含中文字形,未指定中文字体 | 生成报告前设置 matplotlib.rcParams['font.sans-serif']=['Microsoft YaHei','SimHei'] 与 rcParams['axes.unicode_minus']=False |
服务器/容器里报 no display name and no $DISPLAY | 无图形界面,matplotlib 默认交互后端不可用 | 切到 Agg 后端(matplotlib.use('Agg')),只把图保存成文件,不要调用 plt.show() |
报 ModuleNotFoundError: No module named 'matplotlib',但明明装过 | 包装进了另一个 Python 解释器或另一个虚拟环境 | 统一用 python -m pip install 装到当前解释器,跑报告前打印 sys.executable 核对路径 |
| benchmark 传进去报错,或相对指标明显不合理 | ticker 拼写错误或已失效;传入的 Series 与策略收益不同频、索引未对齐 | 先单独验证基准序列能取到且与策略同日历,再生成报告;口径不一致的相对指标没有意义 |
| 报告没出现在预期目录 | 输出参数未生效,或脚本的当前工作目录和设想的不一样 | 输出目录写绝对路径,生成后用 os.getcwd() 打印实际落盘位置 |
| Windows 下带中文的路径报「文件名、目录名或卷标语法不正确」 | 中文路径直接作为参数传给解释器/可执行文件时容易解析失败 | 输出目录改用英文短路径(如 D:\qs_reports\),中文只放在报告标题里 |
报告本身是工具的产物,能不能对外交付取决于你有没有把口径和边界写清楚。
| 报告里的内容 | 交付前必须核对什么 | 为什么 |
|---|---|---|
| 指标数字(夏普、索提诺、最大回撤等) | 样本期、收益频率、无风险利率假设是否写在同一页 | 同一策略换样本期或换频率,结论可能反转 |
| 基准对比曲线 | 基准是否与策略的市场和风格匹配 | 基准选错会把市场 beta 说成自己的超额收益 |
| 净值曲线 | 是否计入交易成本与滑点 | 未计成本的回测净值偏乐观,必须显式说明 |
| 月度收益热力图 | 样本期长度是否足够 | 样本太短时热力图观感好但统计意义弱 |
| 报告中的结论文字 | 策略逻辑有没有未来函数、股票池有没有幸存者偏差 | 数据与逻辑层面的问题 QuantStats 不会替你发现 |
| 免责声明 | 是否随报告一起交付,而不是只写在邮件里 | 必须写明历史表现不代表未来、不构成投资建议 |
| 工具许可与数据来源 | 保留 Apache-2.0 许可与版权声明;行情数据的使用条款单独确认 | 工具免费且允许商用与修改,但数据合规责任在使用方 |
报告的价值在「按时出现」,所以重点是固定输入、固定输出位置、失败能被发现。
1. 固定输入:stock.to_csv('returns_600519.csv') —— 把当次用的收益序列落盘,后续出报告不再重复拉数据。预期输出:一个含日期与收益两列的 CSV 文件。
2. 写一个生成脚本 make_report.py:读 CSV → 调 qs.reports.html(returns, 'SPY') → 输出到带日期的文件名。预期输出:运行一次即产出一份 HTML 报告。
3. 定时触发:Windows 用「任务计划程序」、Linux 用 cron,在复盘日执行 python make_report.py。预期输出:无需人工打开脚本,报告按计划出现在归档目录。
4. 生成后自检:脚本末尾检查文件是否存在、大小是否大于 0、修改时间是否为本次运行时间。预期输出:异常时打印明确报错,而不是静默「成功」。
5. 归档:把 HTML 报告与当次收益序列 CSV 放在同一目录。预期输出:任何一期的报告都能连同原始数据被复现,而不是只剩一张图。
| 归档项 | 建议做法 | 为什么 |
|---|---|---|
| 文件命名 | quantstats_report_YYYY-MM-DD.html | 含日期可排序,回溯时不必逐个打开 |
| 存放目录 | 按 reports/年/月/ 分层 | 避免单目录堆几千个文件导致检索变慢 |
| 生成频率 | 与调仓或复盘节奏一致(如每月首个交易日) | 报告节奏绑定决策节奏才有意义 |
| 失败监控 | 每次生成后校验文件存在且非 0 字节 | 无 GUI 环境下最容易静默失败 |
| 数据快照 | 同时保存当次收益序列 CSV | 报告里的图无法反推原始数据 |
| 保留策略 | 保留最近若干期,更早的压缩归档 | 兼顾事后追溯与磁盘占用 |
报告是算出来的,不是权威结论。对外交付前做下面六个动作,能挡掉大部分「数字对不上」的尴尬。
| 校验项 | 具体怎么做 | 对不上说明什么 |
|---|---|---|
| 最大回撤 | 把序列累计成净值,逐点算相对历史高点的跌幅,取最小值 | 差异大说明序列里混了非收益列,或复权口径与预期不同 |
| 年化收益 | 用 (末值/初值)^(252/交易日数)-1 粗算一次 | 差异大通常是频率假设不符,月频数据按日频年化必然失真 |
| 交易日数量 | 数一下序列长度,与样本期的实际交易日数比对 | 缺口多说明数据缺行,波动与回撤会被系统性低估 |
| 起止日期 | 打印序列的第一个与最后一个索引 | 与预期不一致说明取数区间写错了,结论自然不可比 |
| 缺失与零值 | 统计 NaN 个数与 0 值个数 | NaN 多来自停牌或数据断档,会让指标直接算成 NaN |
| 无风险利率 | 确认生成报告时有没有显式传入 | 未显式传时夏普口径取默认值,跨报告比较会不一致 |
同样一份「指标 + 图」的报告,不同路线的准备工作差别很大,先想清楚自己属于哪一类。
| 路线 | 要准备什么 | 适合谁 | 局限 |
|---|---|---|---|
| 自己备数据 + 用本库 | Python 环境 + 一份收益序列 + 两三行代码 | 已有数据、要求可复现与批量出报告 | 数据可得性与质量由你自己负责 |
| 用 yfinance 直接取数 | 环境 + 一条 download_returns 调用 | 研究美股、想最快跑出第一份报告 | 需要能访问外网数据源;A股不在覆盖范围 |
| 用 akshare/tushare 供数 | 多装一个取数库 + 一段取数脚本 | 研究 A股/港股,需要本地可复现的数据快照 | 多一层数据适配与口径对齐工作 |
| 自己用 matplotlib 拼 | 逐张画图 + 自己排版 + 自己实现指标 | 版式需要高度定制、不介意维护成本 | 指标口径与图表维护都要自己扛 |
| 对话式免部署路线 | 装好客户端 + 一句话描述需求 | 临时分析、手边没有 Python 环境 | 输出是自然语言结论与图表,不是可归档的 HTML tearsheet |
| 专业报表系统 | 采购 + 配置 + 数据接入 + 权限管理 | 机构级交付、需要多人协作与留痕 | 成本与实施周期最高,个人研究过重 |
qs.reports.html 会生成 HTML tearsheet 文件,可用 savefig 等参数控制输出路径;确切参数名以官方 README / 仓库文档为准。若需 PDF,可在浏览器打开后打印为 PDF。
不必。传入基准 ticker(如 'SPY')或 pandas Series 时报告含基准对比,不传则仅展示策略自身绩效,具体以官方实现为准。
官方 README 提及 HTML 与 TeX 相关能力;PDF 通常需自行转换(如浏览器打印 HTML),没有直接 PDF 出口的公开说明,以官方文档为准。
不能。报告仅代表历史收益序列表现,不构成收益保证或投资建议;实盘需自行核验数据、成本与风险。
不能。它只对给定的收益序列做统计与绘图,不负责策略逻辑、撮合与成本模拟。正常分工是:回测框架或你自己的脚本产出收益序列,报告工具负责把这份序列变成可读、可归档的绩效报告,两者是上下游关系;具体能力边界以官方仓库说明为准。
QuantStats 生成的是自包含 HTML/TeX 绩效报告(tearsheet);而对话式免部署路线(本机已核验的技能目录,见对比页)输出自然语言结论与图表,没有对应的 HTML tearsheet 生成技能。两者无已证实集成,是两条独立路线。