概率化回测:策略评估的贝叶斯视角
标准回测给出点估计。概率化回测使用贝叶斯推断,给你一个策略真实表现可能是什么样子的分布——包括不确定性。
回测给了你一个数字。「Sharpe 比率:1.43。」但这个数字实际上告诉你什么?
它告诉你策略在回测期间的实现 Sharpe。它没有告诉你:
- 策略的真实 Sharpe(这个永远无法观测)
- 这个估计中的不确定性
- 策略未来实现类似表现的可能性
贝叶斯方法将回测视为对待估 Sharpe 参数 θ 的推断:计算后验分布 P(θ | data),用它对未来表现做概率陈述。
贝叶斯设置
先验:在看到任何数据之前,我们对策略 Sharpe 的信念。合理的先验是:
如果没有先验信息,可以使用平坦先验(μ₀ = 0,σ₀ → ∞)。如果有领域知识(例如,「大多数股票多空策略的 Sharpe 在 0.3 到 1.0 之间」),可以将其编码进去。
似然:给定 θ,观察到我们的回测收益的概率。对于近似正态的收益:
或者更常见的是,我们直接处理 Sharpe 比率。在 i.i.d. 正态收益的假设下:
其中 γ 是策略的偏度,T 是观测数。
后验:使用贝叶斯定理:
对于正态先验和正态似然,后验也是正态:
其中:
实用实现
import numpy as np
from scipy import stats
def bayesian_sharpe(returns, mu0=0.0, sigma0=10.0, periods_per_year=252):
"""
Compute posterior distribution of Sharpe ratio using Bayesian inference.
Parameters
----------
returns : array
Strategy returns (daily or appropriate frequency)
mu0 : float
Prior mean Sharpe
sigma0 : float
Prior standard deviation of Sharpe
periods_per_year : int
Number of return periods per year
Returns
-------
posterior_mean : float
Posterior mean Sharpe
posterior_std : float
Posterior std of Sharpe
prob_positive : float
P(Sharpe > 0 | data)
prob_gt_1 : float
P(Sharpe > 1 | data)
"""
T = len(returns)
mu = np.mean(returns) * periods_per_year
var = np.var(returns, ddof=1) * periods_per_year
obs_sharpe = mu / np.sqrt(var) if var > 0 else 0.0
var_sharpe = (1 + 0.5 * stats.skew(returns)**2) / T
posterior_var = 1 / (1/sigma0**2 + 1/var_sharpe)
posterior_mean = posterior_var * (mu0/sigma0**2 + obs_sharpe/var_sharpe)
posterior_std = np.sqrt(posterior_var)
prob_positive = 1 - stats.norm.cdf(0, loc=posterior_mean, scale=posterior_std)
prob_gt_1 = 1 - stats.norm.cdf(1.0, loc=posterior_mean, scale=posterior_std)
return {
'posterior_mean': posterior_mean,
'posterior_std': posterior_std,
'prob_positive': prob_positive,
'prob_gt_1': prob_gt_1,
'credible_interval_95': (
posterior_mean - 1.96 * posterior_std,
posterior_mean + 1.96 * posterior_std
)
}
后验告诉了你什么
P(Sharpe > 0 | data):策略有任何正表现的概率。P(Sharpe > 0) 为 95% 是「策略可能有效」的合理阈值。低于 80% 应该让你怀疑。
P(Sharpe > 1 | data):策略达到「好」Sharpe 的概率。这是一个更高的门槛。P(Sharpe > 1) 为 50% 意味着策略有均等的概率是平庸的和优秀的——数据无法区分。
95% 可信区间:与置信区间不同,可信区间有直接解释:「给定数据,我们相信真实 Sharpe 有 95% 的概率落在这个范围内。」对于频率主义置信区间,正确的解释更为复杂。
后验预测分布
一旦有了后验,你可以模拟未来表现。对于每次抽取 θ ~ P(θ | data),从 N(θ·σ, σ²) 模拟 T_new 个未来收益,并计算模拟的 Sharpe。模拟 Sharpe 的分布是后验预测分布:
def posterior_predictive_sharpe(returns, n_simulations=10000, periods_per_year=252):
"""
Simulate future Sharpe ratios from posterior predictive distribution.
"""
result = bayesian_sharpe(returns, periods_per_year=periods_per_year)
future_sharpes = []
for _ in range(n_simulations):
theta_draw = np.random.normal(result['posterior_mean'], result['posterior_std'])
T_new = len(returns)
future_returns = np.random.normal(theta_draw / np.sqrt(periods_per_year),
1.0 / np.sqrt(periods_per_year),
T_new)
future_sharpe = np.mean(future_returns) * np.sqrt(periods_per_year) / np.std(future_returns)
future_sharpes.append(future_sharpe)
return np.array(future_sharpes)
这告诉你未来 Sharpe 比率的范围,结合了回测不确定性和未来方差。
为什么点估计会误导
回测 Sharpe 1.43 看起来很棒。但如果:
- 95% 可信区间是 [0.2, 2.6]
- P(Sharpe > 1) = 35%
那么你的策略可能在平庸和优秀之间,真实 Sharpe 可能在 0.2 也可能在 2.6,回测数据无法区分。你应该相应地调整仓位规模,而不是按好像 1.43 是保证的那样去赌。
在我们的平台上,每个回测报告都显示贝叶斯后验以及点估计。我们认为这比假装不确定性不存在更诚实。
常见陷阱
有信息时使用平坦先验:如果你知道策略是股票多空,Sharpe 3.0 是不合理的。在先验中编码这个——它会使你的后验更合理,减少对嘈杂回测的过拟合。
忽略似然错误设定:正态 Sharpe 分布假设 i.i.d. 收益。金融收益有厚尾、序列相关和结构性变化。后验仍然有用,但概率应被视为近似值,而非精确值。
混淆后验与预测:后验 P(θ | data) 是你对不可观测的真实 Sharpe 的信念。后验预测 P(未来 Sharpe | data) 包含了关于未来收益的额外不确定性。将后验均值作为预期未来 Sharpe 报告会低估不确定性。
在知识体系中的位置
概率化回测是频率主义 PBO 方法的贝叶斯补充。PBO 回答「你最佳策略是假阳性的概率是多少?」贝叶斯推断回答「给定我的数据,策略真实表现的分布是什么?」两者都有用;它们回答的是不同的问题。
《Sharpe 比率崇拜》涵盖了为什么单一 Sharpe 点估计具有误导性。《多重检验》涵盖了如何调整测试了许多策略的情况。本文为你提供了诚实不确定性量化的框架。
参考文献
- Gelman, Carlin, Stern, Rubin, Bayesian Data Analysis, 第 4 章. CRC Press, 2014. ISBN: 978-1439840955.
- Murphy, Probabilistic Machine Learning: An Introduction, 第 4-5 章. MIT Press, 2023. ISBN: 978-0262046824.
- Lopez de Prado, “Bayesian Testing of Trading Strategies,” Journal of Financial Data Science, 2020.