QuantStats · quantstats.stats

QuantStats绩效指标:夏普/最大回撤/索提诺等 60+ 指标用法

quantstats.stats 提供约 60 个绩效与风险指标:夏普比率、索提诺、最大回撤、波动率、VaR/CVaR、胜率、盈亏比、卡玛比率、信息比率、凯利准则等,覆盖收益、风险、回撤、尾部风险与胜率维度。

收益
Sharpe/CAGR
风险
Volatility/VaR
回撤
MaxDrawdown
胜率
WinRate

QuantStats stats 指标分类示意;基于官方 README,非官方指标图。

Core metrics

QuantStats 核心绩效指标有哪些?对照表

依据官方 README stats 方法列表(约 60 个指标,此处列高频核心项)。

指标方法含义适用场景注意点
夏普比率qs.stats.sharpe(returns)单位总波动的超额收益横评不同策略的风险调整收益同时惩罚上行与下行波动,对非正态收益有偏
索提诺比率qs.stats.sortino(returns)只按下行波动调整的超额收益更关注下跌风险、讨厌上行波动被扣分的场景需要明确下行波动口径,结果对阈值敏感
调整后索提诺qs.stats.adjusted_sortino(returns)校正后的索提诺比率对收益分布偏度/峰度敏感的更稳健口径以官方实现口径为准
卡玛比率qs.stats.calmar(returns)年化收益 / 最大回撤衡量每单位最大回撤换来的收益对最大回撤极其敏感,回撤越大指标越差
最大回撤qs.stats.max_drawdown(returns)历史峰值到谷底的最大跌幅评估最坏情况下的亏损承受力只反映历史单次最差,不预测未来
波动率qs.stats.volatility(returns)收益率标准差(年化)衡量整体价格波动幅度不含方向,只测波动大小
VaR / CVaRqs.stats.value_at_risk / conditional_value_at_risk在险价值 / 期望损失(尾部风险)机构风控常用的尾部风险度量依赖置信度与分布假设,CVaR 比 VaR 更保守
胜率 / 盈亏比qs.stats.win_rate / win_loss_ratio正收益期占比 / 盈亏比例策略择时/选股的方向性评估按「收益期」而非逐笔交易口径(见下方说明)
盈亏因子qs.stats.profit_factor(returns)正收益和 / 负收益和衡量盈利期相对亏损期的累计强度比率口径,需结合胜率一起看
凯利准则qs.stats.kelly_criterion(returns)理论上的下注比例上限仓位管理参考,非实际下单建议对收益估计极敏感,实盘常需减半(半凯利)
Quick usage

QuantStats 指标怎么用?四步实操

从导入到多指标组合,四步即可落地;返回值为该指标在当前收益序列下的标量结果。

1. 导入并扩展 pandas:import quantstats as qs; qs.extend_pandas() —— 把指标方法挂到 pandas Series 上,之后可直接 stock.sharpe()。

2. 获取收益序列:stock = qs.utils.download_returns('META') —— 下载 META 的日收益序列;也可换成你自己的 pd.Series。

3. 计算夏普:qs.stats.sharpe(stock) 或扩展后 stock.sharpe() —— 返回单位风险的超额收益(示例值 0.76,仅为演示,非真实承诺)。

4. 组合多指标:qs.stats.sortino(stock)、qs.stats.max_drawdown(stock)、qs.stats.calmar(stock) —— 一次算出下行调整收益、最大回撤与卡玛比率,交叉印证策略风险。

Metric families

QuantStats 指标分哪几类?约 60 个方法清单

按分析目的分成六类,每类列代表方法与用途;完整列表以 dir(qs.stats) 输出为准。

分类代表方法分析用途
收益cagr / expected_return / comp / compsum / geometric_mean / ghpr / ror / avg_return看策略「赚了多少、多快」,衡量复利与累计增长
风险调整sharpe / sortino / adjusted_sortino / calmar / rar / risk_return_ratio / information_ratio把收益「除以风险」,比较不同风险水平下的性价比
风险/尾部volatility / value_at_risk(var) / conditional_value_at_risk(cvar) / tail_ratio / expected_shortfall / skew / kurtosis量化波动与极端亏损,评估尾部风险与分布形态
回撤max_drawdown / drawdown_details / to_drawdown_series / recovery_factor / ulcer_index度量峰值回撤与恢复能力,反映最大亏损与回血速度
胜率/盈亏win_rate / win_loss_ratio / avg_win / avg_loss / profit_factor / payoff_ratio / consecutive_wins / consecutive_losses拆解盈利期与亏损期的结构,判断择时/选股质量
其他/进阶kelly_criterion / r_squared / greeks / implied_volatility / risk_of_ruin / montecarlo 系列 / outliers 系列仓位管理、期权希腊字母、破产概率、离群值等专项
Selection

什么场景该用哪些 QuantStats 指标?

不同分析目的对应不同指标,避免「一把尺子量所有策略」。

分析目的 / 场景推荐指标为什么选它注意点
整体性价比sharpe / calmar / rar把收益除以风险,横评不同策略的风险调整后表现rf 与年化周期必须两边一致,否则不可比
下行风险sortino / adjusted_sortino只惩罚下跌波动,更贴合「怕亏」的心理与实际风险区间内全为上涨时下行波动为 0,指标无意义
回撤承受max_drawdown / ulcer_index直接看最坏回撤与回撤持续时间,评估持有体验日线口径不含盘中低点,盘中浮亏可能更深
尾部风险value_at_risk / conditional_value_at_risk / tail_ratio量化极端亏损概率,机构风控常用依赖置信度与样本长度,样本太短会剧烈跳变
相对基准information_ratio / r_squared / rolling_beta衡量相对基准的超额收益与跟踪敏感度策略与基准交易日历必须对齐,否则结果为 nan
仓位管理kelly_criterion / risk_of_ruin估算理论仓位比例与破产概率,仅作参考对历史收益估计极敏感,实盘常用半凯利
低频(周/月调仓)cagr / volatility / calmar低频样本点少,比率型指标噪声大,更适合看年化与回撤要显式声明年化周期(月频与日频不可混算)
只关心极端亏损conditional_value_at_risk / expected_shortfall / tail_ratioCVaR 描述「最差那部分」的平均亏损,比 VaR 更保守口径以官方实现为准,跨平台对比前先统一置信度
Boundary

Period-Based 与 Trade-Based 口径有什么区别?

关键口径:QuantStats 分析「收益率序列」(日/周/月收益),不是逐笔交易数据。因此:

1. Win Rate = 正收益期占比,而非逐笔胜率。

2. Consecutive Wins/Losses = 连续正/负收益期,而非连续盈利/亏损交易。

3. Payoff Ratio = 平均正收益期 / 平均负收益期,而非单笔盈亏均值比。

4. Profit Factor = 正收益和 / 负收益和,按周期聚合而非按笔聚合。

典型差异:对定期再平衡的系统化策略,周期口径是有效的;但对持仓多日的自由交易者,周期口径会「拆碎」单笔交易——例如一笔 5 日交易可能被计为 3 个正收益日 + 2 个负收益日,此时周期口径的胜率/盈亏因子与逐笔口径会有偏差,需据此解读。
风险提示:以上指标仅代表历史收益序列表现,不构成收益保证或投资建议,实盘需自行核验。
Troubleshooting

QuantStats 指标算出 NaN 或 inf 怎么排查?

指标为 NaN / inf 或数值离谱时,先怀疑收益序列本身,而不是指标方法。下表按「现象 → 常见原因 → 怎么判断 → 怎么处置」四列排查。

现象 / 报错常见原因怎么判断怎么处置
qs.stats.sharpe() 返回 nan收益序列含缺失值(停牌、假期、拼接不同数据源未对齐)returns.isna().sum() 不为 0先 returns.dropna() 再算;跨市场数据先对齐交易日历
多个指标同时变 inf 或 -inf序列含 -100% 或超过 ±100% 的异常收益(复权、拆股未处理)returns.min() / returns.max() 出现极端值改用复权价重算;-100% 会让几何收益与波动率无定义
夏普高得不符合常识用了周频/月频序列却按日频周期年化看序列频率与调用时传入的年化参数按频率显式声明年化周期(月频 12、周频 52,口径以官方实现为准)
sortino() / adjusted_sortino() 为 nan样本区间内没有负收益,下行波动为 0(returns < 0).any() 为 False换含下跌的更长区间;全正收益序列的下行指标本身无意义
信息比率、滚动 beta 全为 nan策略与基准的日期索引不一致(时区、交易日不同)stock.index.equals(benchmark.index) 为 False先 reindex / align 到同一交易日历,再算相对指标
VaR 结果随置信度剧烈跳变样本太短,尾部样本点不足看 len(returns) 与收益分布直方图扩大样本,或同时给 CVaR 做对照,避免单点结论
指标之间自相矛盾(夏普高但回撤深)收益分布非正态、尖峰厚尾,波动率低估了真实风险看 qs.stats.skew() 与 kurtosis()补看 sortino、cvar、ulcer_index,不要用单指标下结论

1. 先给收益序列做体检:print(returns.isna().sum(), returns.min(), returns.max(), returns.index.freq) —— 一次看清缺失、极值、频率三个最容易出问题的点。预期输出:缺失计数、最小值、最大值与索引频率。

2. 再检查基准是否对齐:bench = qs.utils.download_returns('SPY'); print(returns.index.equals(bench.index)) —— 输出 False 说明两条序列不在同一交易日历上,此时任何相对指标都不可信。

3. 最后统一年化口径复算:按序列频率显式声明年化周期后重算 qs.stats.sharpe(returns) —— 与默认调用结果对照,两者差值就是口径带来的误差,而不是策略差异。

经验次序:先删缺失、再剔极值、然后对齐日历、最后统一年化——四步按顺序做完,绝大多数 NaN/inf 会自然消失。若仍为 NaN,再回头确认传入的确实是收益率序列(而非价格序列),具体口径以官方实现为准。
Reconciliation

QuantStats 算出的指标和别人算的不一样,差在哪?

同一份收益序列,QuantStats 与国内行情软件、其他回测框架的结果常有差异,差异大多来自年化方式、无风险利率、回撤粒度三类口径。下表给对账思路,具体以各方文档与官方实现为准。

指标QuantStats 口径要点别处常见的口径差异从哪来怎么核对
夏普比率按收益率序列与调用时传入的无风险利率参数计算(默认值以官方实现为准)部分平台固定扣减一年期定存或国债利率无风险利率取值不同,低波动策略差异被放大两边都固定 rf 后再比,记录 rf 取值
年化收益(CAGR)由收益序列频率推导年化有的平台按自然日 365 天折算交易日与自然日年化的差异,在短样本上尤其明显先统一年化周期,再看数值是否收敛
最大回撤基于净值峰谷,按传入数据的粒度计算有的平台用盘中价或复权后净值数据粒度不同,盘中口径往往回撤更深用同一份日线净值复算,确认粒度和复权方式
波动率收益率标准差并按频率年化有的用对数收益、有的用简单收益收益计算方式不同,长期序列差异会累积先统一收益计算方式,再比波动率
胜率正收益「期」占比,统计单元是收益周期交易软件多为逐笔交易胜率周期口径与交易口径本质不同,不是谁算错先确认统计单元,再决定能不能直接比
卡玛比率年化收益 ÷ 最大回撤有的在分子上再扣无风险利率分子口径不同,结果系统性偏移确认分子是否扣无风险利率,注明再比
信息比率超额收益 ÷ 跟踪误差,需要显式传入基准序列有的直接用某个指数收益当基准基准标的与频率不一致时,跟踪误差完全不同对齐基准与频率后再比,注明基准标的
对账顺序:先对齐数据(区间、频率、复权)→ 再统一口径(无风险利率、年化周期、统计单元)→ 最后才比数值。任何一步没对齐,比出来的差值都不代表策略差异,只代表口径差异。各平台口径以其文档为准,QuantStats 口径以官方实现为准。
Minimal repro

怎么把 QuantStats 指标算成一页对照表?

从一条收益序列到可直接存档的指标表,五步即可复现;每步给出命令、说明与预期输出形态。

1. 准备收益序列:import quantstats as qs; stock = qs.utils.download_returns('META') —— 得到日频收益序列,也可以换成自己的 pd.Series(索引为交易日)。预期输出:一个日频 Series,长度等于区间内交易日数。

2. 清洗:stock = stock.dropna() —— 去掉缺失日后,指标才不会被 NaN 污染。预期输出:长度略减,stock.isna().sum() 为 0。

3. 组装指标字典:把 qs.stats.sharpe(stock)、qs.stats.sortino(stock)、qs.stats.max_drawdown(stock)、qs.stats.calmar(stock)、qs.stats.volatility(stock)、qs.stats.value_at_risk(stock) 放进同一个 dict —— 一次拿到收益、下行、回撤、尾部四类代表指标。

4. 落成表格:pd.DataFrame([metrics]).T.to_markdown() —— 得到可直接贴进研究记录的 Markdown 指标表(依赖 tabulate,官方依赖清单里已包含)。预期输出:一张 6 行的指标表。

5. 出报告对照:qs.reports.html(stock, 'SPY') —— 把指标与图表打包成 HTML,便于与同事核对同一份区间。预期输出:生成一个 HTML 文件,浏览器打开即可查看。

指标这张表里该看什么常见误读结论怎么写才站得住
夏普比率与同区间、同无风险利率的其他策略横向比拿不同频率、不同 rf 的夏普直接比大小写清样本区间、频率与 rf 取值,再给数值
索提诺比率只关心下行波动时的风险调整收益当成「更宽松的夏普」直接替换使用与夏普并列给出,差异大时说明上行波动来自哪里
最大回撤最坏持有体验与回撤恢复时间当作未来最大亏损的上限标注为历史单次最差值,并说明数据粒度
波动率整体波动幅度,用于横向比较把波动率当成风险的全部补上尾部指标(VaR/CVaR)一起写
胜率 / 盈亏因子方向性与盈亏结构的稳定性与逐笔交易胜率混着讲注明统计单元是收益周期,不是单笔交易
卡玛比率每单位最大回撤换来的年化收益与夏普混用,不看分母是什么说明分母是最大回撤而非波动率
下一步分工:指标怎么算看本页;怎么把指标和图打包成报告见报告生成;怎么和基准比相对绩效见基准对比;图形怎么选见可视化。工具链怎么装见安装。
FAQ

常见问题有哪些?

QuantStats 有多少个指标?

quantstats.stats 模块约 60 个方法,覆盖收益、风险、风险调整、回撤、尾部风险、胜率盈亏等,具体以官方 README 的 dir(qs.stats) 列表为准。

夏普比率怎么算?

qs.stats.sharpe(returns) 或扩展 pandas 后 returns.sharpe(),返回单位风险的超额收益;默认参数与年化口径以官方实现为准。

索提诺和夏普有什么区别?

夏普用总波动(含上行),索提诺只按下行波动惩罚;更怕下跌风险时可优先看 sortino/adjusted_sortino,具体口径以官方实现为准。

Win Rate 是逐笔胜率吗?

不是。它是「正收益期占比」,按收益率序列周期(日/周/月)计算,非逐笔成交口径;对持仓多日的自由交易者会有偏差。

这些指标和 EasyClaw 的量化分析一样吗?

本机 quant-analyst 技能也能输出 Sharpe、最大回撤等风险指标,但它是独立的量化研究路线,与 QuantStats 无已证实集成,输出形式与口径可能不同,选择时需自行比对。

指标结果能用于实盘吗?

不能。绩效指标仅代表历史收益序列表现,不构成投资建议或收益保证,实盘需自行核验数据、成本与风险。

算完指标之后怎么生成报告?

用 qs.reports.html(stock, benchmark) 把指标和图打包成 HTML 报告。