风险度量指标:最大回撤、夏普比率、索提诺比率、卡玛比率

做量化交易,说白了就是在风险和收益之间找平衡。

我见过太多人,只看收益率就冲进去,结果亏得底裤都不剩。你想想看,一个策略年化50%,但最大回撤40%,你敢上仓位吗?

所以,今天咱们就来聊聊四个最常用的风险度量指标。我会用Python把它们算得明明白白。

一、最大回撤(Max Drawdown)

最大回撤,是我个人最看重的指标。它告诉你:在最倒霉的情况下,你会亏多少钱。

公式其实很简单:从净值曲线的某个高点,到后续最低点的最大跌幅。

核心公式:

最大回撤 = max( (高点 - 低点) / 高点 )

嗯,这里要注意:回撤不是从最高点到最低点那么简单。它必须是「先有高点,后有低点」的序列关系。

import numpy as np
import pandas as pd

def max_drawdown(equity_curve):
    """
    计算最大回撤
    equity_curve: 净值序列(pandas Series 或 list)
    """
    # 计算累计最大值
    rolling_max = np.maximum.accumulate(equity_curve)
    # 计算回撤序列
    drawdown = (equity_curve - rolling_max) / rolling_max
    # 取最小值(最大回撤)
    max_dd = drawdown.min()
    return max_dd, drawdown

# 示例
np.random.seed(42)
equity = 100 * np.exp(np.cumsum(np.random.normal(0.001, 0.02, 252)))
max_dd, dd_series = max_drawdown(equity)
print(f"最大回撤: {max_dd:.2%}")

我的经验: 我在项目中遇到过,有些策略回撤只有5%,但持续了半年。这种「温水煮青蛙」式的回撤,比短期暴跌更可怕。所以,我还会额外看「回撤恢复时间」。

二、夏普比率(Sharpe Ratio)

夏普比率,说白了就是「每承担一单位风险,能换来多少超额收益」。

它假设收益是正态分布的,但现实嘛...你懂的,厚尾分布才是常态。

公式:

Sharpe = (Rp - Rf) / σp

其中 Rp 是策略年化收益,Rf 是无风险利率,σp 是年化波动率

def sharpe_ratio(returns, risk_free_rate=0.03, periods_per_year=252):
    """
    计算夏普比率
    returns: 日收益率序列
    risk_free_rate: 年化无风险利率(默认3%)
    """
    # 年化超额收益
    excess_return = np.mean(returns) * periods_per_year - risk_free_rate
    # 年化波动率
    volatility = np.std(returns) * np.sqrt(periods_per_year)
    sharpe = excess_return / volatility
    return sharpe

# 示例
daily_returns = np.random.normal(0.001, 0.02, 252)
sr = sharpe_ratio(daily_returns)
print(f"夏普比率: {sr:.2f}")

避坑指南: 我曾经用日频数据算夏普,结果发现年化后数值特别高。后来才意识到,如果收益率序列有自相关性,直接用日频算会高估夏普。建议先用月频数据,或者做Newey-West调整。

三、索提诺比率(Sortino Ratio)

索提诺比率,是夏普比率的「升级版」。它只惩罚下行风险,不惩罚上行波动。

我个人觉得,这才是更合理的风险度量。你想想看,上涨的波动是好事啊,为什么要惩罚它?

公式:

Sortino = (Rp - Rf) / σ_down

其中 σ_down 是下行标准差(只考虑负收益)

def sortino_ratio(returns, risk_free_rate=0.03, target_return=0, periods_per_year=252):
    """
    计算索提诺比率
    target_return: 目标收益率(通常设为0或无风险利率)
    """
    # 年化超额收益
    excess_return = np.mean(returns) * periods_per_year - risk_free_rate
    # 计算下行偏差
    downside_returns = returns[returns < target_return]
    if len(downside_returns) == 0:
        return np.inf  # 没有下行风险,完美!
    downside_std = np.std(downside_returns) * np.sqrt(periods_per_year)
    sortino = excess_return / downside_std
    return sortino

# 示例
sr_sortino = sortino_ratio(daily_returns)
print(f"索提诺比率: {sr_sortino:.2f}")

我的习惯: 我会把目标收益率设成无风险利率,而不是0。因为如果策略连无风险收益都跑不赢,那还不如买国债。

四、卡玛比率(Calmar Ratio)

卡玛比率,是「收益/最大回撤」的比值。它很直观:你愿意承受多大的回撤,去换取多少收益?

这个指标在CTA策略中特别常用。为什么?因为CTA策略的回撤往往很大,但收益也高。卡玛比率能很好地衡量这种「以险换利」的效率。

公式:

Calmar = 年化收益率 / 最大回撤(绝对值)

def calmar_ratio(equity_curve, periods_per_year=252):
    """
    计算卡玛比率
    """
    # 年化收益率
    total_return = equity_curve[-1] / equity_curve[0] - 1
    years = len(equity_curve) / periods_per_year
    annual_return = (1 + total_return) ** (1 / years) - 1
    # 最大回撤
    max_dd, _ = max_drawdown(equity_curve)
    # 卡玛比率
    calmar = annual_return / abs(max_dd)
    return calmar

# 示例
cr = calmar_ratio(equity)
print(f"卡玛比率: {cr:.2f}")

注意: 卡玛比率对回测周期很敏感。如果回测时间短,最大回撤可能还没暴露出来。我一般要求至少3年的回测数据,卡玛比率才有参考价值。

五、四个指标对比

指标 衡量什么 优点 缺点
最大回撤 最坏情况下的亏损 直观、容易理解 只关注一个点,忽略过程
夏普比率 风险调整后收益 标准化、可比较 假设正态分布,不区分涨跌
索提诺比率 下行风险调整后收益 只惩罚坏波动 需要足够多的负收益样本
卡玛比率 收益/最大回撤 直接反映风险承受意愿 对回测周期敏感

六、知识体系图

下面这张图,帮你理清这四个指标的关系和适用场景:

风险度量指标知识体系 风险度量指标 最大回撤 夏普比率 索提诺比率 卡玛比率 核心用途 衡量最坏亏损 评估风险承受能力 资金管理参考 核心用途 风险调整后收益 策略横向对比 标准化评估 核心用途 只惩罚下行风险 更合理的风险度量 适合非对称策略 核心用途 收益/最大回撤 CTA策略常用 直观反映效率 使用建议 没有完美的指标,建议四个指标综合使用 结合回测周期、策略类型、资金规模综合判断

七、综合实战:一键计算所有指标

最后,我把这四个指标封装成一个函数。你在实盘或回测时,直接调用就行。

def risk_metrics(equity_curve, daily_returns, risk_free_rate=0.03):
    """
    综合计算四个风险指标
    equity_curve: 净值序列
    daily_returns: 日收益率序列
    """
    metrics = {}
    
    # 最大回撤
    max_dd, _ = max_drawdown(equity_curve)
    metrics['最大回撤'] = f"{max_dd:.2%}"
    
    # 夏普比率
    sr = sharpe_ratio(daily_returns, risk_free_rate)
    metrics['夏普比率'] = f"{sr:.2f}"
    
    # 索提诺比率
    sortino = sortino_ratio(daily_returns, risk_free_rate)
    metrics['索提诺比率'] = f"{sortino:.2f}"
    
    # 卡玛比率
    calmar = calmar_ratio(equity_curve)
    metrics['卡玛比率'] = f"{calmar:.2f}"
    
    return metrics

# 使用示例
result = risk_metrics(equity, daily_returns)
for k, v in result.items():
    print(f"{k}: {v}")

最后说一句: 这些指标只是工具,不是圣杯。我见过夏普3.0的策略,实盘一个月就崩了。为什么?因为回测数据太短,或者参数过拟合。所以,永远保持怀疑,永远做压力测试。

专注资料整理