量化新手入门:一文搞懂 QuantStats 量化分析框架
本文专为量化新手设计,带你完整体验 QuantStats 搭建A股分析框架。通过Tushare获取实时行情数据,结合TA-Lib计算MACD、RSI等技术指标,逐步实现策略开发、回测验证与绩效评估。内容涵盖环境配置、数据准备、收益可视化、多策略对比等基础实战,并引入交易成本建模、参数优化等实用技巧,配套代码示例与常见问题解答,助你快速掌握A股量化分析核心技能。
文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。适合量化新手建立系统认知,为策略开发打下基础。
第一部分 环境配置与数据准备
本部分推荐参考:QuantStats + TA-Lib:量化策略分析入门实战的五阶段构建之旅 🔥
阶段 1:环境配置与数据准备
1.1 安装依赖库
pip install quantstats==0.0.62 pandas==2.0.2 numpy==1.26.4 tushare==1.4.19 # 基础库
1.2 获取A股数据(以沪深300指数为例)
import tushare as ts
import pandas as pd
# 获取沪深300指数日线数据
df = pro.index_daily(ts_code="000300.SH", start_date="20180101", end_date="20231231")
df["date"] = pd.to_datetime(df["trade_date"])
df.set_index("date", inplace=True)
df.sort_index(inplace=True)
# 计算收益率(QuantStats要求收益率序列)
returns = df["pct_chg"].dropna() / 100 # Tushare返回的是百分比,需转换为小数
1.3 使用TA-Lib生成技术指标
import talib
# 示例:计算RSI和MACD
df["rsi"] = talib.RSI(df["close"], timeperiod=14)
df["macd"], df["macd_signal"], _ = talib.MACD(df["close"])
# 生成交易信号(简单策略:RSI<30买入,RSI>70卖出)
df["signal"] = 0
df.loc[df["rsi"] < 30, "signal"] = 1
df.loc[df["rsi"] > 70, "signal"] = -1
# 计算策略收益率
strategy_returns = df["signal"].shift(1) * returns
第二部分 QuantStats核心应用
2.1 指标计算
import quantstats as qs
# 计算核心指标
print(f"年化收益率: {qs.stats.cagr(strategy_returns):.2%}")
print(f"夏普比率: {qs.stats.sharpe(strategy_returns):.2f}")
print(f"最大回撤: {qs.stats.max_drawdown(strategy_returns):.2%}")
# 对比基准(沪深300)
benchmark_rets = returns # 假设基准与策略使用相同数据
qs.reports.metrics(strategy_returns, benchmark=benchmark_rets, mode="basic")
2.2 可视化分析
# 绘制收益曲线与回撤
qs.plots.returns(strategy_returns, benchmark_rets)
qs.plots.drawdown(strategy_returns)
# 滚动夏普比率
qs.plots.rolling_sharpe(strategy_returns, periods=90)
# 月度收益热力图
qs.plots.monthly_heatmap(strategy_returns)
2.3 生成完整报告
# HTML格式报告
qs.reports.html(
returns=strategy_returns,
benchmark=benchmark_rets,
output="./reports/a_stock_report.html",
title="A股策略分析报告",
)
# 控制台完整报告
qs.reports.full(strategy_returns, benchmark_rets)
第三部分 进阶实践
3.1 自定义指标组合
custom_stats = [
"cagr",
"max_drawdown",
"calmar",
"sortino",
"win_rate",
"profit_factor",
]
qs.reports.metrics(strategy_returns, benchmark=benchmark_rets, metrics=custom_stats)
3.2 结合TA-Lib的深度分析
# 计算波动率指标
df["atr"] = talib.ATR(df["high"], df["low"], df["close"], timeperiod=14)
# 动态风险调整
volatility = df["atr"].pct_change().dropna()
adjusted_returns = strategy_returns / volatility
# 评估调整后表现
qs.reports.metrics(adjusted_returns)
第四部分 最佳实践指南
- 数据质量检查
# 检查缺失值
print(f"缺失值数量: {returns.isnull().sum()}")
# 处理极端值
clean_returns = qs.stats.remove_outliers(strategy_returns)
- 参数调优验证
# 滚动窗口分析
rolling_volatility = qs.stats.rolling_volatility(strategy_returns)
rolling_volatility.plot(title="滚动收益波动率")
- 多周期分析
# 不同时间维度分析
periods = {
"全周期": slice(None),
"牛市(2019-2021)": slice("2019-01-01", "2021-12-31"),
"熊市(2022)": slice("2022-01-01", "2022-12-31"),
}
# 表现分析
for name, period in periods.items():
qs.reports.metrics(strategy_returns.loc[period])
- 异常处理
try:
qs.stats.kelly_criterion(strategy_returns)
except Exception as e:
print(f"凯利准则计算异常: {str(e)}")
# 回退到夏普比率
print(f"夏普比率: {qs.stats.sharpe(strategy_returns)}")
第五部分 事件驱动回测集成
5.1 构建事件驱动框架
class EventBacktester:
def __init__(self, data):
self.data = data
self.positions = pd.Series(0, index=data.index)
self.cash = 1000000 # 初始资金
self.trade_log = []
def apply_strategy(self, strategy_func):
signals = strategy_func(self.data)
self.positions = signals.shift(1).fillna(0)
def calculate_equity(self):
# 计算每日收益
strategy_returns = self.positions * self.data["pct_chg"] / 100
equity = (1 + strategy_returns).cumprod() * self.cash
return equity.dropna()
# 示例策略
def rsi_strategy(data):
rsi = talib.RSI(data["close"], timeperiod=14)
return (rsi < 30).astype(int) - (rsi > 70).astype(int)
# 执行回测
backtester = EventBacktester(df)
backtester.apply_strategy(rsi_strategy)
equity_curve = backtester.calculate_equity()
5.2 交易成本建模
def calculate_equity_with_cost(self, commission=0.0003, slippage=0.0002):
position_changes = self.positions.diff().fillna(0)
trade_volume = position_changes.abs() * self.data["close"]
# 计算成本
commission_cost = trade_volume * commission
slippage_cost = trade_volume * slippage
# 调整收益
net_returns = (
self.positions * self.data["pct_chg"] / 100
- (commission_cost + slippage_cost) / self.cash
)
return (1 + net_returns).cumprod() * self.cash
# 比较有无成本的差异
equity_with_cost = calculate_equity_with_cost(backtester)
qs.plots.returns(equity_curve.pct_change(), equity_with_cost.pct_change())
第六部分 实时监控系统实现
6.1 实时数据获取
import schedule
import time
def realtime_monitor():
# 获取最新行情
new_data = pro.index_daily(
ts_code="000300.SH", start_date=pd.Timestamp.now().strftime("%Y%m%d")
)
# 更新数据集
global df
df = pd.concat([df, new_data])
# 生成实时报告
qs.reports.html(df["pct_chg"], output="realtime_report.html")
# 设置定时任务(每30分钟执行)
schedule.every(30).minutes.do(realtime_monitor)
while True:
schedule.run_pending()
time.sleep(60)
6.2 预警系统集成
ddef risk_monitor(returns):
current_drawdown = qs.stats.to_drawdown_series(returns).iloc[-1]
volatility = qs.stats.volatility(returns)
if current_drawdown < -0.1:
send_alert("回撤超过10%预警!")
if volatility > 0.25:
send_alert("波动率超过25%预警!")
def send_alert(message):
# 实现邮件/短信通知逻辑
print(f"[ALERT] {pd.Timestamp.now()} {message}")
# 在实时监控中添加
def enhanced_monitor():
returns = df["pct_chg"].dropna() / 100
risk_monitor(returns[-30:]) # 监控最近30天
第七部分 性能优化策略
7.1 向量化加速计算
# 使用Numpy加速指标计算
def vectorized_rsi(prices, window=14):
deltas = np.diff(prices)
gain = deltas.copy()
loss = deltas.copy()
gain[gain < 0] = 0
loss[loss > 0] = 0
avg_gain = np.convolve(gain, np.ones(window)/window, mode='valid')
avg_loss = np.convolve(-loss, np.ones(window)/window, mode='valid')
rs = avg_gain / avg_loss
return 100 - (100 / (1 + rs))
# 性能对比
%timeit talib.RSI(df['close'], 14) # TA-Lib实现
%timeit vectorized_rsi(df['close'].values, 14) # Numpy实现
7.2 并行计算优化
from concurrent.futures import ThreadPoolExecutor
import random
def run_strategy(rsi_buy, rsi_sell):
"""
简单模拟策略回测:
- 假设根据 RI 买卖信号生成随机收益和交易次数
- 实际应用中需替换为真实的策略逻辑
"""
# 模拟计算收益(此处为示例随机值)
total_return = (rsi_sell - rsi_buy) * 0.1 + random.uniform(-1, 1)
# 模拟交易次数(随机生成10-20次交易)
num_trades = random.randint(10, 20)
# 模拟胜率(40%-60%)
win_rate = random.uniform(0.4, 0.6)
return {
"rsi_buy": rsi_buy,
"rsi_sell": rsi_sell,
"total_return": round(total_return, 2),
"num_trades": num_trades,
"win_rate": round(win_rate, 2),
}
def parallel_backtest(params_list):
results = []
with ThreadPoolExecutor() as executor:
futures = []
for params in params_list:
futures.append(
executor.submit(run_strategy, rsi_buy=params[0], rsi_sell=params[1])
)
for future in futures:
results.append(future.result())
return pd.DataFrame(results)
# 参数网格示例
params_grid = [(25, 75), (30, 70), (20, 80)]
results_df = parallel_backtest(params_grid)
# 打印结果
print(results_df)
第九部分 常见问题解决方案
9.1 数据对齐问题
# 处理多时间序列对齐
def align_data(strategy_ret, benchmark_ret):
common_index = strategy_ret.index.intersection(benchmark_ret.index)
return strategy_ret.loc[common_index], benchmark_ret.loc[common_index]
# 示例
aligned_returns, aligned_bench = align_data(strategy_returns, benchmark_rets)
9.2 异常值处理
def winsorize_returns(returns, std=3):
mean = returns.mean()
std_dev = returns.std()
lower = mean - std * std_dev
upper = mean + std * std_dev
return returns.clip(lower, upper)
cleaned_returns = winsorize_returns(strategy_returns)
9.3 复权处理
# 获取前复权数据
df_adj = pro.pro_bar(ts_code="600519.SH", adj="qfq", start_date="20180101")
df_adj["ret"] = df_adj["close"].pct_change().dropna()
附录 QuantStats方法速览
quantstats.stats 指标方法列表
[f for f in dir(qs.stats) if f[0] != '_']
方法名称 | 中文名称 | 作用 |
---|---|---|
adjusted_sortino | 调整索提诺比率 | 对索提诺比率进行修正,考虑更复杂的风险调整。 |
autocorr_penalty | 自相关惩罚 | 对策略收益的自相关性进行惩罚,调整风险指标。 |
avg_loss | 平均亏损 | 计算所有亏损交易的平均亏损值。 |
avg_return | 平均收益 | 计算策略的平均收益率。 |
avg_win | 平均盈利 | 计算所有盈利交易的平均盈利值。 |
best | 最佳收益 | 策略在指定周期内的最高单期收益。 |
cagr | 年复合增长率 | 计算策略的年化复合增长率。 |
calmar | 卡尔玛比率 | 年复合增长率与最大回撤的比率。 |
common_sense_ratio | 常识比率 | 结合收益和风险的综合评估指标。 |
comp | 复合收益 | 计算策略的累计复合收益。 |
compare | 对比 | 将策略与其他基准(如指数)进行对比分析。 |
compsum | 累计复合和 | 计算策略的累计复合收益总和。 |
conditional_value_at_risk | 条件风险价值(CVaR) | 衡量在极端损失情况下的平均损失(尾部风险)。 |
consecutive_losses | 连续亏损次数 | 统计策略连续亏损的次数。 |
consecutive_wins | 连续盈利次数 | 统计策略连续盈利的次数。 |
cpc_index | CPC指数 | 综合评估策略的风险调整后收益。 |
cvar | 条件风险价值 | 同conditional_value_at_risk 。 |
distribution | 收益分布 | 分析策略收益的统计分布特征。 |
drawdown_details | 回撤详情 | 提供策略历史回撤的详细数据(如开始时间、持续时间等)。 |
expected_return | 预期收益 | 基于历史数据计算策略的预期收益。 |
expected_shortfall | 预期缺口 | 同conditional_value_at_risk ,衡量尾部风险。 |
exposure | 风险敞口 | 计算策略在市场中的风险暴露程度。 |
gain_to_pain_ratio | 收益痛苦比率 | 总收益与总亏损的比率,衡量策略的盈亏平衡能力。 |
geometric_mean | 几何平均收益 | 计算策略的几何平均收益率。 |
ghpr | 几何平均持有期收益 | 基于几何平均的持有期收益率。 |
greeks | 希腊值 | 计算期权相关的希腊值(如Delta、Gamma)。 |
implied_volatility | 隐含波动率 | 基于期权价格反推的波动率。 |
information_ratio | 信息比率 | 衡量超额收益与跟踪误差的比率。 |
kelly_criterion | 凯利准则 | 计算最优投资比例以最大化长期增长率。 |
kurtosis | 峰度 | 衡量收益分布的尖峭程度(极端值风险)。 |
max_drawdown | 最大回撤 | 策略从峰值到谷值的最大亏损幅度。 |
monthly_returns | 月度收益 | 展示策略的月度收益数据。 |
omega | Omega比率 | 衡量收益超过阈值的概率与不足概率的比率。 |
outlier_loss_ratio | 异常亏损比率 | 异常亏损事件占总亏损的比例。 |
outlier_win_ratio | 异常盈利比率 | 异常盈利事件占总盈利的比例。 |
outliers | 异常值 | 识别策略收益中的异常值(极端收益或亏损)。 |
payoff_ratio | 盈亏比 | 平均盈利与平均亏损的比率。 |
pct_rank | 百分比排名 | 当前收益在历史收益中的百分比排名。 |
probabilistic_adjusted_sortino_ratio | 概率调整索提诺比率 | 结合概率方法调整的索提诺比率。 |
probabilistic_ratio | 概率比率 | 基于概率模型评估策略表现。 |
probabilistic_sharpe_ratio | 概率夏普比率 | 计算夏普比率的统计显著性(概率形式)。 |
probabilistic_sortino_ratio | 概率索提诺比率 | 计算索提诺比率的统计显著性(概率形式)。 |
profit_factor | 盈利因子 | 总盈利与总亏损的比率。 |
profit_ratio | 盈利比率 | 盈利交易数量与总交易数量的比率。 |
r2 | 决定系数(R²) | 衡量策略收益与基准收益的拟合优度。 |
r_squared | 决定系数 | 同r2 。 |
rar | 风险调整后收益 | 综合考虑风险后的收益评估指标。 |
recovery_factor | 恢复因子 | 累计收益与最大回撤的比率,衡量回撤恢复能力。 |
remove_outliers | 剔除异常值 | 在计算指标时剔除异常值的影响。 |
risk_of_ruin | 破产风险 | 衡量策略导致全部亏损的概率。 |
risk_return_ratio | 风险收益比率 | 收益与风险的比率(通常以波动率衡量)。 |
rolling_greeks | 滚动希腊值 | 计算滚动窗口内的期权希腊值。 |
rolling_sharpe | 滚动夏普比率 | 计算滚动窗口内的夏普比率。 |
rolling_sortino | 滚动索提诺比率 | 计算滚动窗口内的索提诺比率。 |
rolling_volatility | 滚动波动率 | 计算滚动窗口内的收益波动率。 |
ror | 破产风险 | 同risk_of_ruin 。 |
serenity_index | 平静指数 | 综合波动率、偏度和峰度的风险调整后指标。 |
sharpe | 夏普比率 | 衡量投资回报与总风险的比率。 |
skew | 偏度 | 衡量收益分布的不对称性。 |
smart_sharpe | 智能夏普比率 | 对夏普比率进行自相关性和其他偏差的修正。 |
smart_sortino | 智能索提诺比率 | 对索提诺比率进行自相关性和其他偏差的修正。 |
sortino | 索提诺比率 | 类似夏普比率,但仅考虑下行风险。 |
tail_ratio | 尾部比率 | 正收益与负收益尾部风险的比率。 |
to_drawdown_series | 回撤序列 | 生成策略历史回撤的序列数据。 |
treynor_ratio | 特雷诺比率 | 衡量超额收益与系统性风险(Beta)的比率。 |
ulcer_index | 溃疡指数 | 衡量策略回撤的深度和持续时间。 |
ulcer_performance_index | 溃疡绩效指数 | 结合溃疡指数的风险调整后收益指标。 |
upi | 溃疡绩效指数 | 同ulcer_performance_index 。 |
value_at_risk | 风险价值(VaR) | 衡量在特定置信水平下的最大潜在损失。 |
var | 风险价值 | 同value_at_risk 。 |
volatility | 波动率 | 计算策略收益的标准差(衡量风险)。 |
warn | 警告 | 检测策略可能存在的问题并发出警告。 |
win_loss_ratio | 胜负比 | 盈利交易数量与亏损交易数量的比率。 |
win_rate | 胜率 | 盈利交易占总交易的比例。 |
worst | 最差收益 | 策略在指定周期内的最低单期收益。 |
quantstats.plots 图表方法列表
[f for f in dir(qs.plots) if f[0] != '_']
方法名称 | 中文名称 | 作用 |
---|---|---|
daily_returns | 日度收益图 | 展示策略的每日收益率随时间变化的折线图。 |
distribution | 收益分布图 | 显示策略收益的统计分布(直方图或密度图),分析收益的集中性和偏态。 |
drawdown | 回撤曲线图 | 绘制策略从峰值到谷值的回撤百分比曲线,展示历史回撤幅度。 |
drawdowns_periods | 回撤周期图 | 展示每个回撤周期的持续时间、深度及恢复情况。 |
earnings | 累计收益图 | 显示策略的累计收益随时间变化的曲线。 |
histogram | 收益直方图 | 用直方图形式展示收益分布的频率。 |
log_returns | 对数收益率图 | 展示策略的对数收益率(Log Returns)变化趋势。 |
monthly_heatmap | 月度收益热力图 | 用颜色热力图展示策略在月度时间尺度上的收益表现。 |
monthly_returns | 月度收益图 | 显示策略的月度收益柱状图或表格。 |
plotly | 交互式图表 | 生成交互式图表(基于Plotly),支持动态缩放和细节查看。 |
returns | 收益率时序图 | 绘制策略收益率的时间序列图。 |
rolling_beta | 滚动贝塔值图 | 展示策略与基准之间的滚动贝塔值(系统性风险)。 |
rolling_sharpe | 滚动夏普比率图 | 显示滚动窗口内夏普比率的变化趋势。 |
rolling_sortino | 滚动索提诺比率图 | 显示滚动窗口内索提诺比率的变化趋势。 |
rolling_volatility | 滚动波动率图 | 展示滚动窗口内收益波动率(标准差)的变化。 |
snapshot | 综合快照图 | 生成策略表现的综合图表,包含收益、回撤、风险指标等关键信息。 |
to_plotly | 转换为Plotly图表 | 将现有图表转换为Plotly交互式图表格式。 |
warnings | 策略警告图 | 可视化策略潜在问题的警告信息(如过度拟合、高风险区间等)。 |
yearly_returns | 年度收益图 | 展示策略的年度收益柱状图或表格。 |
部分图表示例说明
-
月度热力图 (
monthly_heatmap
)
类似日历热力图,用颜色深浅表示不同月份的收益正负和强度,直观显示月度表现。 -
滚动指标图 (
rolling_beta
,rolling_sharpe
等)
展示滚动窗口(如30天、90天)内特定指标的变化,帮助分析策略的稳定性。 -
回撤周期图 (
drawdowns_periods
)
可能以条形图或表格形式列出每次回撤的开始时间、结束时间、持续天数及最大回撤值。 -
综合快照图 (
snapshot
)
通常包含多个子图,如收益曲线、回撤曲线、月度收益分布等,用于快速总览策略表现。
注意事项
plotly
和to_plotly
的区别可能在于:前者直接生成交互图表,后者将现有静态图表转换为Plotly格式。log_returns
与普通收益率图的差异在于对数收益更适用于长期趋势分析(可叠加性)。
quantstats.report 报告方法列表
[f for f in dir(qs.reports) if f[0] != '_']
方法名称 | 中文名称 | 作用 |
---|---|---|
StringIO | 字符串缓冲区报告 | 将报告内容输出到内存中的字符串缓冲区(io.StringIO 对象),便于后续处理或保存。 |
basic | 基础报告 | 生成策略的核心指标摘要报告(如夏普比率、最大回撤、年化收益等)。 |
full | 完整报告 | 生成包含详细分析和扩展指标的综合报告(涵盖统计、风险、绩效等)。 |
html | HTML格式报告 | 生成HTML格式的策略报告,支持网页直接查看或嵌入到Web应用中。 |
iDisplay | 交互式显示 | 在Jupyter Notebook等环境中直接交互式显示报告(自动渲染为可视化格式)。 |
iHTML | 交互式HTML嵌入 | 生成可嵌入到Jupyter Notebook的交互式HTML内容(支持动态图表)。 |
metrics | 指标汇总报告 | 生成策略关键指标的表格化汇总(如收益率、波动率、风险调整后收益等)。 |
plots | 图表集成报告 | 生成包含可视化图表的报告(如收益曲线、回撤图、分布直方图等)。 |
relativedelta | 相对时间计算 | 处理时间偏移计算(如基于相对日期生成报告的时间范围)。 |
补充说明
-
StringIO
适用于需要将报告内容保存为字符串的场景(例如通过API返回或写入数据库),而非直接生成文件。 -
iDisplay 与 iHTML
iDisplay
:自动在Jupyter中渲染报告为可交互的HTML组件。iHTML
:返回HTML字符串,可手动嵌入到Notebook单元格或Web页面。
-
relativedelta
通常用于动态调整报告的时间范围(例如生成过去12个月的滚动报告),依赖dateutil.relativedelta
库的时间计算功能。 -
basic vs full
basic
:简洁版,包含核心指标(如夏普比率、CAGR、最大回撤)。full
:扩展版,增加更多细节(如月度收益表、风险指标分解、交易统计)。
-
plots
可能集成多个图表方法(如plots.monthly_heatmap
、plots.drawdown
),生成组合式可视化报告。
风险提示与免责声明
本文内容基于公开信息研究整理,不构成任何形式的投资建议。历史表现不应作为未来收益保证,市场存在不可预见的波动风险。投资者需结合自身财务状况及风险承受能力独立决策,并自行承担交易结果。作者及发布方不对任何依据本文操作导致的损失承担法律责任。市场有风险,投资须谨慎。