4. 核心指标(上):计算收益率、波动率、最大回撤、夏普比率
做量化交易,说白了就是跟数字打交道。但数字本身不会说话,得靠指标来解读。
这一章,我们来聊聊四个最基础、也最核心的指标:收益率、波动率、最大回撤、夏普比率。我个人习惯把它们叫做「四大金刚」——你只要做策略,就绕不开它们。
核心观点:这四个指标分别回答了四个问题——赚了多少?稳不稳?亏过多少?性价比如何?
4.1 收益率:最直观的「成绩单」
收益率,谁都会算。但我要说的是,计算方式不同,结果可能差很多。
简单收益率 vs 对数收益率
简单收益率就是 (P_t - P_{t-1}) / P_{t-1}。这个好理解,你买100块的东西涨到110,收益率就是10%。
但我个人更推荐用对数收益率,也就是 ln(P_t / P_{t-1})。为什么?
- 可加性:对数收益率可以直接相加得到总收益率,简单收益率不行
- 正态性更好:对数收益率更接近正态分布,方便后续建模
- 对称性:涨10%再跌10%,简单收益率算出来是亏的,对数收益率是0
我的习惯:做回测时用对数收益率计算,展示给客户时用简单收益率——因为客户更习惯「涨了10%」这种说法。
import numpy as np
import pandas as pd
# 假设我们有收盘价数据
prices = pd.Series([100, 102, 101, 105, 110])
# 简单收益率
simple_returns = prices.pct_change().dropna()
# 对数收益率
log_returns = np.log(prices / prices.shift(1)).dropna()
print("简单收益率:", simple_returns.values)
print("对数收益率:", log_returns.values)
4.2 波动率:风险的「体温计」
波动率衡量的是收益率的离散程度。说白了,就是看你的策略稳不稳。
年化波动率的计算
日波动率乘以根号下交易天数,就得到年化波动率。A股一般用252个交易日,港股用250,美股用252。
嗯,这里要注意:如果你用的是对数收益率,直接算标准差就行。如果是简单收益率,理论上应该用几何平均,但实践中大家也都用标准差——差别不大。
避坑指南:我曾经在计算波动率时忘记年化,结果夏普比率算出来是0.8,看起来还不错。后来发现是日波动率直接当成年波动率用了——实际只有0.05。那叫一个尴尬。
# 计算年化波动率
daily_vol = log_returns.std()
annual_vol = daily_vol * np.sqrt(252)
print(f"日波动率: {daily_vol:.4f}")
print(f"年化波动率: {annual_vol:.4f}")
4.3 最大回撤:最痛的「伤疤」
最大回撤,就是净值从最高点跌到最低点的最大幅度。这个指标我特别看重——因为它直接关系到你能不能拿住策略。
你想想看,一个策略年化收益30%,但最大回撤40%。你敢投吗?反正我不敢。回撤太大,心态先崩了。
计算逻辑
- 计算累计净值(从1开始)
- 计算历史最高点(滚动最大值)
- 回撤 = (当前净值 - 历史最高) / 历史最高
- 最大回撤 = 所有回撤中的最小值(负的最大)
# 计算最大回撤
cumulative = (1 + log_returns).cumprod()
running_max = cumulative.cummax()
drawdown = (cumulative - running_max) / running_max
max_drawdown = drawdown.min()
print(f"最大回撤: {max_drawdown:.2%}")
重要提醒:最大回撤是一个「事后指标」。它告诉你历史上最惨的时候亏了多少,但不代表未来不会更惨。所以,我一般会在最大回撤的基础上再加一个安全边际——比如策略最大回撤20%,我按30%来评估风险。
4.4 夏普比率:性价比之王
夏普比率 = (策略收益率 - 无风险利率) / 波动率
这个指标衡量的是「每承担一单位风险,能获得多少超额收益」。说白了,就是性价比。
无风险利率怎么选?
- 国内常用:一年期国债收益率(目前约2%左右)
- 或者用:SHIBOR 3个月利率
- 也有人直接用0——我个人不太建议,因为这样会高估夏普比率
夏普比率多少算好?
| 夏普比率 | 评价 |
|---|---|
| < 0.5 | 一般般,不如买理财 |
| 0.5 - 1.0 | 还不错,可以考虑 |
| 1.0 - 2.0 | 优秀,值得关注 |
| > 2.0 | 小心!可能是过拟合 |
我的经验:实盘中夏普比率能稳定在1.0以上,就已经是顶级策略了。回测里动不动就3.0、5.0的,十有八九是过拟合。我曾经见过一个回测夏普8.0的策略,实盘直接亏了30%——嗯,从那以后我对高夏普特别警惕。
# 计算夏普比率
risk_free_rate = 0.02 # 假设无风险利率2%
excess_return = log_returns.mean() * 252 - risk_free_rate
sharpe_ratio = excess_return / annual_vol
print(f"年化超额收益: {excess_return:.2%}")
print(f"夏普比率: {sharpe_ratio:.2f}")
4.5 实战:一次性计算所有指标
来,我们把上面这些整合成一个函数。这样以后每次回测完,直接调用就行。
def calculate_metrics(prices, risk_free_rate=0.02, trading_days=252):
"""
计算核心指标
prices: 收盘价序列
risk_free_rate: 无风险利率(年化)
trading_days: 年交易天数
"""
# 对数收益率
log_returns = np.log(prices / prices.shift(1)).dropna()
# 年化收益率
annual_return = log_returns.mean() * trading_days
# 年化波动率
annual_vol = log_returns.std() * np.sqrt(trading_days)
# 最大回撤
cumulative = (1 + log_returns).cumprod()
running_max = cumulative.cummax()
drawdown = (cumulative - running_max) / running_max
max_drawdown = drawdown.min()
# 夏普比率
excess_return = annual_return - risk_free_rate
sharpe = excess_return / annual_vol if annual_vol != 0 else 0
return {
'年化收益率': f"{annual_return:.2%}",
'年化波动率': f"{annual_vol:.2%}",
'最大回撤': f"{max_drawdown:.2%}",
'夏普比率': f"{sharpe:.2f}"
}
# 使用示例
result = calculate_metrics(prices)
for k, v in result.items():
print(f"{k}: {v}")
这四个指标,是量化分析的基石。你掌握了它们,就能对任何一个策略做出初步判断。下一章我们会继续讲其他核心指标,比如卡玛比率、索提诺比率等等——但说实话,这四个是最常用的,先把它们吃透。
总结一下:
- 收益率:看赚了多少,推荐用对数收益率
- 波动率:看稳不稳,记得年化
- 最大回撤:看亏过多少,要留安全边际
- 夏普比率:看性价比,太高要警惕过拟合