第十九章:回测框架:评估指标(准确率、召回率、夏普比率)
回测做完了,策略跑了一堆曲线,然后呢?
说实话,我见过不少交易员,回测曲线画得漂漂亮亮,一问具体指标就支支吾吾。嗯,这其实挺危险的。回测不是看个净值曲线就完事了,你得用科学的指标去衡量它——到底这个策略是真的能赚钱,还是纯粹运气好?
这一章,我们就来聊聊回测框架里最核心的三个评估指标:准确率、召回率、夏普比率。我个人习惯把它们分成两类来看——一类看“能不能抓到机会”,另一类看“赚得值不值得”。
19.1 准确率与召回率:你的策略到底准不准?
先说说准确率和召回率。这两个指标最早是从分类模型里来的,但在波动率曲面异常点检测这个场景下,它们非常实用。
准确率(Precision),说白了就是:你预测的异常点里,有多少是真的异常?
公式很简单:
Precision = TP / (TP + FP)
其中 TP 是真正例(你预测异常,实际也异常),FP 是假正例(你预测异常,实际正常)。
召回率(Recall),则是:所有真正的异常点里,你抓到了多少?
Recall = TP / (TP + FN)
FN 是假负例(你漏掉的异常点)。
我在项目中遇到过一件事。有一次我开发了一个波动率曲面异常检测模型,准确率高达 95%,我挺高兴的。结果一查召回率,只有 30%。什么意思?就是它虽然报的异常点基本都对,但漏掉了七成真正的异常。这在交易里是很要命的——你错过了太多该规避的风险。
核心观点:准确率和召回率要一起看。单独看一个,容易被误导。
19.2 F1 分数:一个折中的好办法
那有没有一个指标能综合这两者?有,F1 分数。
F1 = 2 * (Precision * Recall) / (Precision + Recall)
F1 是准确率和召回率的调和平均数。它不会让你偏科。如果你只追求准确率而忽略召回率,F1 会很低;反过来也一样。
我个人习惯在回测报告里同时展示这三个指标。准确率告诉你“别乱报”,召回率告诉你“别漏报”,F1 告诉你“整体水平”。
19.3 夏普比率:赚得多不如赚得稳
好,现在我们知道策略能不能抓到异常点了。但抓到之后呢?赚了多少?风险多大?
这就轮到夏普比率登场了。
夏普比率(Sharpe Ratio)衡量的是:每承担一单位风险,你能获得多少超额收益。
Sharpe Ratio = (Rp - Rf) / σp
其中:
- Rp:策略年化收益率
- Rf:无风险利率(通常用国债收益率)
- σp:策略年化波动率(风险)
你想想看,如果一个策略年化收益 30%,但波动率高达 40%,夏普比率只有 0.75。另一个策略年化收益 15%,波动率只有 10%,夏普比率是 1.5。哪个更好?我个人更倾向于后者。为什么?因为波动率低,意味着回撤小,持有体验好,你更容易坚持执行下去。
实战小技巧:我一般要求策略的夏普比率至少大于 1.0,最好在 1.5 以上。低于 1.0 的策略,说实话,风险调整后的收益不太够看。
19.4 一个完整的回测评估示例
光说不练假把式。我们写一段 Python 代码,把这三个指标算出来。
import numpy as np
import pandas as pd
def calculate_precision_recall(y_true, y_pred):
"""
计算准确率和召回率
y_true: 真实标签(1=异常,0=正常)
y_pred: 预测标签
"""
tp = np.sum((y_true == 1) & (y_pred == 1))
fp = np.sum((y_true == 0) & (y_pred == 1))
fn = np.sum((y_true == 1) & (y_pred == 0))
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1 = 2 * precision * recall / (precision + recall) if (precision + recall) > 0 else 0
return precision, recall, f1
def calculate_sharpe_ratio(returns, risk_free_rate=0.02):
"""
计算夏普比率
returns: 策略日收益率序列
risk_free_rate: 年化无风险利率
"""
excess_returns = returns - risk_free_rate / 252 # 转换为日度
sharpe = np.sqrt(252) * excess_returns.mean() / returns.std()
return sharpe
# 模拟数据
np.random.seed(42)
y_true = np.random.choice([0, 1], size=1000, p=[0.95, 0.05])
y_pred = np.random.choice([0, 1], size=1000, p=[0.9, 0.1])
precision, recall, f1 = calculate_precision_recall(y_true, y_pred)
print(f"准确率: {precision:.3f}")
print(f"召回率: {recall:.3f}")
print(f"F1 分数: {f1:.3f}")
# 模拟收益率
daily_returns = np.random.normal(0.001, 0.02, 1000)
sharpe = calculate_sharpe_ratio(daily_returns)
print(f"夏普比率: {sharpe:.3f}")
这段代码很简单,但很实用。你把它集成到你的回测框架里,每次跑完策略,自动输出这几个指标,一目了然。
19.5 知识体系图
为了让你更直观地理解这几个指标之间的关系,我画了一张图:
19.6 避坑指南
最后,分享几个我踩过的坑:
- 不要只看夏普比率。 夏普比率高不代表策略一定好。如果策略用了高杠杆,夏普比率可能被扭曲。我一般会同时看最大回撤和卡玛比率(Calmar Ratio)。
- 准确率和召回率的阈值怎么定? 这取决于你的风险偏好。如果你更怕漏掉异常点(比如风控场景),那就优先保证召回率。如果你更怕误报(比如交易成本高),那就优先保证准确率。
- 样本外测试很重要。 我曾经在样本内跑出过夏普比率 2.5 的策略,一到样本外直接变成 0.3。嗯,过拟合了。所以一定要做样本外测试,或者用交叉验证。
警告: 不要为了美化回测指标而做数据窥探(Data Snooping)。反复调整参数直到指标好看,这叫“曲线拟合”,不是真正的策略开发。
好了,这一章的内容就到这里。准确率、召回率、夏普比率,这三个指标是你回测框架的基石。把它们用好了,你就能更客观地评价自己的策略,而不是凭感觉说“这个策略不错”。
公众号:蓝海资料掘金营,微信deep3321