Skip to content

策略绩效指标

为什么要用指标评价策略

完成了回测之后,你会得到一条净值曲线。仅凭肉眼观察净值曲线的走势来判断策略好坏是不够的——你需要一套量化指标来客观、系统地评价策略表现。

举个简单的例子:策略A在3年内赚了50%,策略B在3年内赚了30%。哪个策略更好?直觉上A更好,但如果A在这个过程中经历了40%的最大回撤(也就是说你的账户一度亏损40%),而B的最大回撤只有10%,很多投资者可能更愿意选择B,因为持有B时心理压力小得多。

所以评价策略不能只看收益,还要看风险、看稳定性、看效率。本章将系统介绍量化投资中最常用的绩效指标。

收益类指标

总收益率(Total Return)

定义:策略在整个回测期间的总收益比例。

公式

总收益率 = (期末净值 - 期初净值) / 期初净值 × 100%

代码实现

python
def total_return(daily_values):
    """计算总收益率"""
    return (daily_values[-1] / daily_values[0] - 1)

参考标准

  • 总收益率本身没有绝对的"好"或"坏"标准,因为它与回测时间段、市场环境有关
  • 如果回测期跨越了一个完整牛熊周期(通常3-5年),总收益率才有参考价值
  • 应该与同期基准指数(如沪深300)对比,看策略是否跑赢了基准

注意:总收益率没有考虑时间因素。50%的总收益率,用1年实现和用10年实现,意义完全不同。

年化收益率(Annualized Return)

定义:将策略的总收益率折算为按年计算的平均收益率。

公式

年化收益率 = (期末净值 / 期初净值) ^ (252 / 交易日数) - 1

其中252是A股大约的年度交易日数。

代码实现

python
import numpy as np

def annualized_return(daily_values, trading_days_per_year=252):
    """计算年化收益率"""
    total_days = len(daily_values)
    if total_days < 2:
        return 0.0
    total_ret = daily_values[-1] / daily_values[0]
    return total_ret ** (trading_days_per_year / total_days) - 1

参考标准

年化收益率评价
< 5%不如买银行理财,策略意义不大
5% ~ 10%一般,需要看风险是否匹配
10% ~ 20%不错,多数优秀基金经理的水平
20% ~ 30%很好,顶尖基金经理水平
> 30%非常优秀,但需警惕过拟合或策略容量问题

注意:年化收益率受回测时段影响很大。如果回测恰好覆盖了一轮大牛市,年化收益率会很高;反之则可能很低。因此,年化收益率需要结合市场环境和基准指数来解读。

风险类指标

最大回撤(Maximum Drawdown)

定义:在回测期间内,账户净值从最高点跌至最低点的最大跌幅。最大回撤衡量的是投资者在最坏情况下可能面临的最大亏损。

公式

最大回撤 = max(1 - 第i天的净值 / 第i天之前的历史最高净值)

代码实现

python
def max_drawdown(daily_values):
    """计算最大回撤"""
    peak = daily_values[0]
    max_dd = 0.0

    for value in daily_values:
        if value > peak:
            peak = value
        dd = (peak - value) / peak
        if dd > max_dd:
            max_dd = dd

    return max_dd

# 使用numpy的向量化实现(更快)
def max_drawdown_vectorized(daily_values):
    """向量化计算最大回撤"""
    arr = np.array(daily_values)
    peak = np.maximum.accumulate(arr)
    drawdown = (peak - arr) / peak
    return drawdown.max()

参考标准

最大回撤评价
< 10%非常稳健,适合保守型投资者
10% ~ 20%可接受,多数股票型基金的水平
20% ~ 30%较大,需要较强的心理承受能力
30% ~ 50%很大,需要评估是否值得承担
> 50%极端风险,策略可能存在严重问题

最大回撤的意义在于:如果你的策略最大回撤是40%,那么在实盘运行中你需要做好准备——你的账户可能在某段时间亏损40%。你是否能在那种情况下坚持策略,不手动干预?如果你不能承受这个幅度的亏损,那么这个策略对你来说风险太大了。

年化波动率(Annualized Volatility)

定义:策略每日收益率的标准差,年化处理后反映策略收益的波动程度。波动率越高,策略的不确定性越大。

公式

日收益率标准差 = std(每日收益率序列)
年化波动率 = 日收益率标准差 × sqrt(252)

代码实现

python
def annualized_volatility(daily_values):
    """计算年化波动率"""
    daily_returns = np.diff(daily_values) / daily_values[:-1]
    return daily_returns.std() * np.sqrt(252)

参考标准

  • 沪深300指数的年化波动率通常在15%-25%之间
  • 如果策略的年化波动率显著高于基准指数,说明策略承担了更大的风险
  • 波动率本身不是"坏"的,关键看波动是否带来了足够的收益补偿

风险调整收益指标

夏普比率(Sharpe Ratio)

夏普比率是评价策略"性价比"的核心指标——每承担一单位风险,能获得多少超额收益。由于夏普比率非常重要,下一章会专门深入讲解,这里先给出基本定义。

公式

夏普比率 = (年化收益率 - 无风险利率) / 年化波动率

参考标准

夏普比率评价
< 0策略跑输无风险收益,不值得考虑
0 ~ 0.5收益不足以补偿风险
0.5 ~ 1.0一般
1.0 ~ 2.0不错
2.0 ~ 3.0优秀
> 3.0卓越,但需要警惕过拟合

Calmar比率

定义:年化收益率与最大回撤的比值。与夏普比率类似,但用最大回撤替代波动率来衡量风险。

公式

Calmar比率 = 年化收益率 / 最大回撤

代码实现

python
def calmar_ratio(daily_values, trading_days_per_year=252):
    """计算Calmar比率"""
    ann_ret = annualized_return(daily_values, trading_days_per_year)
    max_dd = max_drawdown(daily_values)
    if max_dd == 0:
        return float('inf')
    return ann_ret / max_dd

参考标准

Calmar比率评价
< 0.5风险收益比不佳
0.5 ~ 1.0一般
1.0 ~ 2.0不错
2.0 ~ 3.0优秀
> 3.0卓越

Calmar比率的优势在于它用最大回撤来衡量风险,比波动率更直观——投资者更关心"我最坏会亏多少",而不是"收益率的统计离散程度"。

交易统计指标

胜率(Win Rate)

定义:盈利交易次数占总交易次数的比例。

公式

胜率 = 盈利交易次数 / 总交易次数 × 100%

代码实现

python
def win_rate(trades):
    """计算胜率"""
    if len(trades) == 0:
        return 0.0
    winning_trades = [t for t in trades if t['profit'] > 0]
    return len(winning_trades) / len(trades)

参考标准

  • 胜率本身不能单独评价策略好坏。一个胜率30%的策略可能是赚钱的(每次赚的多、亏的少),一个胜率70%的策略可能是亏钱的(每次赚的少、亏的多)
  • 通常来说,趋势跟踪策略的胜率偏低(30%-40%),但盈亏比高
  • 均值回归策略的胜率偏高(50%-60%),但单笔盈亏小
  • 胜率需要与盈亏比结合分析

盈亏比(Profit/Loss Ratio)

定义:平均盈利交易的金额与平均亏损交易金额的比值。

公式

盈亏比 = 平均盈利金额 / 平均亏损金额

代码实现

python
def profit_loss_ratio(trades):
    """计算盈亏比"""
    profits = [t['profit'] for t in trades if t['profit'] > 0]
    losses = [t['profit'] for t in trades if t['profit'] < 0]

    if len(profits) == 0 or len(losses) == 0:
        return float('inf') if len(profits) > 0 else 0.0

    avg_profit = sum(profits) / len(profits)
    avg_loss = abs(sum(losses) / len(losses))

    if avg_loss == 0:
        return float('inf')

    return avg_profit / avg_loss

参考标准

盈亏比评价
< 1.0每次亏的比赚的多,必须靠高胜率弥补
1.0 ~ 1.5一般
1.5 ~ 2.0不错
2.0 ~ 3.0很好
> 3.0优秀

胜率与盈亏比的关系

一个策略能否盈利,取决于胜率和盈亏比的组合。盈亏平衡时的最低胜率为:

盈亏平衡胜率 = 1 / (1 + 盈亏比)
盈亏比盈亏平衡胜率
1.050.0%
1.540.0%
2.033.3%
3.025.0%
5.016.7%

举个例子:如果你的策略盈亏比是2.0(平均每次盈利是平均每次亏损的2倍),那么只要胜率超过33.3%,策略就是盈利的。这就是为什么很多趋势跟踪策略虽然胜率只有30%-40%,但仍然能赚钱——它们的盈亏比通常在2.0以上。

平均持仓天数

定义:从买入到卖出的平均持有天数。

代码实现

python
def avg_holding_days(trades):
    """计算平均持仓天数"""
    if len(trades) == 0:
        return 0
    total_days = sum(t['holding_days'] for t in trades)
    return total_days / len(trades)

意义

  • 平均持仓天数反映了策略的交易频率
  • 短线策略:1-5天
  • 波段策略:5-30天
  • 中线策略:30-90天
  • 长线策略:90天以上

持仓天数越短,交易越频繁,交易成本的累积影响越大。一个日均换仓的策略,每月的交易成本可能就吃掉了大部分收益。

综合指标汇总

下面是一个计算所有绩效指标的完整函数:

python
def calculate_all_metrics(daily_values, trades, risk_free_rate=0.02):
    """计算所有绩效指标"""
    metrics = {}

    # 收益类
    metrics['total_return'] = total_return(daily_values)
    metrics['annualized_return'] = annualized_return(daily_values)

    # 风险类
    metrics['max_drawdown'] = max_drawdown(daily_values)
    metrics['annualized_volatility'] = annualized_volatility(daily_values)

    # 风险调整收益
    excess_return = metrics['annualized_return'] - risk_free_rate
    metrics['sharpe_ratio'] = excess_return / metrics['annualized_volatility'] if metrics['annualized_volatility'] > 0 else 0
    metrics['calmar_ratio'] = metrics['annualized_return'] / metrics['max_drawdown'] if metrics['max_drawdown'] > 0 else float('inf')

    # 交易统计
    if trades:
        metrics['total_trades'] = len(trades)
        metrics['win_rate'] = win_rate(trades)
        metrics['profit_loss_ratio'] = profit_loss_ratio(trades)
        metrics['avg_holding_days'] = avg_holding_days(trades)
    else:
        metrics['total_trades'] = 0
        metrics['win_rate'] = 0
        metrics['profit_loss_ratio'] = 0
        metrics['avg_holding_days'] = 0

    return metrics

def print_metrics(metrics):
    """格式化输出绩效指标"""
    print("=" * 50)
    print("          策略绩效报告")
    print("=" * 50)
    print(f"总收益率:       {metrics['total_return']:.2%}")
    print(f"年化收益率:     {metrics['annualized_return']:.2%}")
    print(f"最大回撤:       {metrics['max_drawdown']:.2%}")
    print(f"年化波动率:     {metrics['annualized_volatility']:.2%}")
    print(f"夏普比率:       {metrics['sharpe_ratio']:.2f}")
    print(f"Calmar比率:     {metrics['calmar_ratio']:.2f}")
    print(f"总交易次数:     {metrics['total_trades']}")
    print(f"胜率:           {metrics['win_rate']:.2%}")
    print(f"盈亏比:         {metrics['profit_loss_ratio']:.2f}")
    print(f"平均持仓天数:   {metrics['avg_holding_days']:.1f}")
    print("=" * 50)

指标使用中常见的误区

误区一:只看收益率不看风险

"年化30%"听起来很诱人,但如果最大回撤50%,你在回撤期间能否坚持持有?大多数人在账户腰斩时已经止损离场了。永远将收益率和风险指标放在一起看。

误区二:过度追求高夏普比率

夏普比率虽然是很好的综合指标,但它有其局限性(下一章详细讨论)。不要为了优化夏普比率而牺牲策略的简洁性和可解释性。

误区三:忽视交易次数的统计显著性

如果你的策略只做了5笔交易,即使胜率80%、年化收益50%,这些数字也没有统计意义。一般来说,至少需要30笔以上的交易才能得出相对可靠的统计结论。

误区四:忽略与基准的对比

策略年化收益10%,看起来一般。但如果同期沪深300下跌20%,那么策略跑赢了基准30个百分点,实际上表现非常好。始终选择一个合适的基准指数进行对比。

下一步

掌握了绩效指标的计算方法后,下一章我们将深入探讨其中最重要的指标——夏普比率,理解它的数学含义、使用方法和局限性。

仅供学习交流,不构成任何投资建议