贝叶斯后验的概率加权估计
BOCPD 贝叶斯后验概率加权估计算法说明
1. 算法背景
BOCPD(Bayesian Online Changepoint Detection,贝叶斯在线变点检测)是 Adams & MacKay (2007) 提出的在线算法,用于实时检测时间序列中的"机制切换"(regime change)。
在交易系统中,它被用于检测价格是否进入了趋势状态。如果检测到强趋势,动量过滤器会在 Layer0 硬拦截开仓信号,避免在剧烈单边行情中逆势交易。
核心问题:给定一段不断增长的 K 线数据,如何实时判断"当前价格是在随机波动,还是在持续朝某个方向移动"?
2. 核心概念
2.1 Run Length(当前 regime 持续长度)
BOCPD 的核心变量是 run length r,表示"距离上一个变点已经过了多少根 K 线"。
- r=0:刚刚发生了变点(regime 切换),一切从头开始
- r=5:当前 regime 已经持续了 5 根 K 线
- r=30:当前 regime 已经持续了 30 根 K 线(约 2.5 小时)
关键设计:算法不确定变点到底在哪里,所以它同时维护所有可能的 run length(r=0, 1, 2, ..., 59),每个 r 都有一个概率 P(r),所有概率之和为 1。
2.2 NIG 后验(Normal-Inverse-Gamma)
对每个 run length r,算法维护一个独立的 NIG 后验分布,用 4 个参数描述:
| 参数 | 含义 |
|---|---|
| μ_r | 该 regime 内收益率的均值估计("漂移"方向和大小) |
| κ_r | 均值估计的精度(观测越多越大,估计越稳定) |
| α_r | 方差估计的自由度参数 |
| β_r | 方差估计的 scale 参数 |
其中 μ_r 是最重要的:它回答了"如果当前 regime 从 r 根 K 线前开始,那这段时间内每根 K 线的平均收益率是多少"。
2.3 Hazard Rate(变点先验概率)
hazard_rate = 0.05,意味着每根 K 线有 5% 的概率发生变点,即平均每 20 根 K 线(约 1.7 小时)出现一次 regime 切换。这是一个先验假设,控制了算法对变点的敏感度。
3. 算法运行流程
3.1 初始状态
_log_probs = [0.0] → P(r=0) = 100%
_suff = [(μ₀=0, κ₀=1, α₀=3, β₀=5e-5)] → 先验:均值为 0,方差很小
只有一个 run length r=0,概率为 100%。先验认为收益率均值为 0(无趋势)。
3.2 每根 K 线的更新(update)
输入:x = log(close / prev_close)(当根 K 线的对数收益率)
步骤 1:计算预测概率
对每个现有 run length r,用它的 NIG 后验计算"观测到 x 的概率":
π(x | r) = Student-t 分布的概率密度
= Student-t_{2α_r}(x; μ_r, β_r(κ_r+1)/(α_r·κ_r))
直觉:如果 r 对应的 regime 能很好地"解释"当前观测 x,那 π(x|r) 就大。
步骤 2:增长概率
如果没有发生变点,run length 加 1:
P(r+1 | 新数据) ∝ P(r | 旧数据) × π(x|r) × (1 - H)
含义:旧的 r 变成 r+1 的概率 = 旧概率 × 观测似然 × 不发生变点的概率(95%)
步骤 3:变点概率
如果发生了变点,run length 重置为 0:
P(r=0 | 新数据) ∝ Σ_r [ P(r | 旧数据) × π(x|r) × H ]
含义:所有旧 run length 都有可能在这一步"断裂",各自贡献 5% 的概率汇总到 r=0。
步骤 4:更新后验参数
对每个 run length,用新观测 x 更新 NIG 后验:
κ_new = κ + 1
μ_new = (κ × μ + x) / κ_new ← 先验均值和观测的加权平均
α_new = α + 0.5
β_new = β + κ(x - μ)² / (2κ_new) ← 方差估计的更新
μ_new 的直觉:它是"旧估计"和"新观测"的加权平均。κ 越大(看过的数据越多),旧估计的权重越大,新观测的影响越小。
步骤 5:归一化 + 截断
所有概率归一化使其和为 1,并截断到 max_run=60 防止无限增长。
3.3 更新过程图示
时刻 t-1 的状态:
r=0: P=0.05, μ₀=0.000
r=1: P=0.15, μ₁=-0.002
r=2: P=0.30, μ₂=-0.003
r=3: P=0.50, μ₃=-0.001
│
▼ 收到新 K 线: x = -0.005 (跌 0.5%)
│
时刻 t 的状态:
r=0: P=0.08, μ₀=0.000 ← 变点:所有旧 r 贡献了 5% 汇聚到这里,后验重置为先验
r=1: P=0.04, μ₁=-0.0025 ← 从旧 r=0 增长来,μ=(1×0 + (-0.005))/2
r=2: P=0.13, μ₂=-0.003 ← 从旧 r=1 增长来,μ=(2×(-0.002) + (-0.005))/3
r=3: P=0.27, μ₃=-0.0035 ← 从旧 r=2 增长来
r=4: P=0.48, μ₄=-0.002 ← 从旧 r=3 增长来(概率最高 → MAP_r=4)
4. 概率加权估计
4.1 drift_mean 的计算
算法不选择某一个 run length,而是对所有 r 的后验均值 μ_r 做概率加权求和:
drift_mean = Σ P(r) × μ_r
= P(r=0)×μ₀ + P(r=1)×μ₁ + P(r=2)×μ₂ + ...
这就是"贝叶斯后验的概率加权估计"——在不确定变点位置的情况下,综合所有可能性得出一个整体的趋势方向和强度估计。
数值示例
| run length r | P(r) | μ_r | P(r) × μ_r |
|---|---|---|---|
| 0 | 5% | 0.0000 | 0.0000 |
| 1 | 60% | -0.0080 | -0.0048 |
| 2 | 15% | -0.0050 | -0.00075 |
| 5 | 10% | -0.0020 | -0.00020 |
| 20 | 8% | -0.0005 | -0.00004 |
| 其他 | 2% | ≈0 | ≈0 |
| 合计 | 100% | -0.00579 |
drift_mean ≈ -0.0058,表示概率加权后的平均漂移为每根 K 线 -0.58%。
注意事项
drift_mean 不等于最近 N 根 K 线收益率的算术平均。它有两个特点:
- 受 MAP run length 主导:如果 MAP_r 很小(如 r=1),那个 r 的 μ 只基于 1-2 个观测,估计不稳定,但概率权重大,容易主导结果
- 混合了不同时间尺度的 regime:短 run length(看最近几根)和长 run length(看最近几十根)的 μ 被混合在一起
因此 drift_mean 应作为趋势方向和强度的定性指标(正=上涨、负=下跌、绝对值大=趋势强),而非精确的"每根 K 线实际平均收益率"。
4.2 trend_probability 的计算
真正决定是否拦截的是 P(trending),它比 drift_mean 更严谨:
P(trending) = Σ P(r) × P(|μ_r 的真实值| > drift_threshold | 后验分布_r)
对每个 r,不是直接看 μ_r 的点估计,而是考虑 μ_r 的不确定性:
μ_r 的后验分布 ~ Student-t_{2α_r}(μ_hat_r, β_r/(α_r·κ_r))
P(trending | r) = P(μ_r > +0.0005) + P(μ_r < -0.0005)
= 后验分布在 ±drift_threshold 之外的面积
- r 小(数据少):后验分布宽,不确定性大。即使 μ_r 看起来偏离 0,也可能是噪声
- r 大(数据多):后验分布窄,如果 μ_r 偏离 0,大概率是真实趋势
最终按 P(r) 加权求和,得到一个综合了所有不确定性的趋势概率。
图示
drift_threshold = ±0.0005
r=1 (数据少,分布宽):
┌─────────────┐
╱│ │╲
╱ │ │ ╲
────╱────│─────────────│────╲────
-0.005 -0.0005 +0.0005 +0.005
← 阴影面积 = P(trending|r=1) ≈ 70% →
r=20 (数据多,分布窄,且均值偏离 0):
┌──┐
╱│ │╲
╱ │ │ ╲
──────────────────╱────│──│────╲──
-0.005 -0.0005 +0.0005 +0.005
← P(trending|r=20) ≈ 98% →
5. 辅助诊断指标
5.1 MAP_r(最大后验 run length)
MAP_r = argmax_r P(r)
概率最高的 run length。MAP_r=1 说明算法认为最可能的情况是"刚发生了变点,当前 regime 才 1 根 K 线"。
5.2 P(cp)(变点概率)
P(cp) = P(r=0)
当前这根 K 线是变点的概率。P(cp)=0.05 说明有 5% 的概率刚刚发生了 regime 切换。
5.3 三个指标的组合解读
| MAP_r | drift_mean | P(cp) | 含义 |
|---|---|---|---|
| 大 | 接近 0 | 低 | 长期震荡,无趋势 |
| 大 | 偏离 0 | 低 | 长期趋势已确立 |
| 小 | 偏离 0 | 低 | 新趋势刚开始,但估计不稳定 |
| 小 | 任意 | 高 | 刚发生变点,regime 正在切换 |
6. 在交易系统中的应用
6.1 拦截逻辑
if P(trending) > 0.8:
硬拦截,不允许开仓
当 BOCPD 判断市场处于趋势状态的概率超过 80% 时,Layer0 直接拦截。这是动量过滤器最顶层的安全门控。
6.2 跨层共享
BOCPD 的 trend_probability 还会传递给下游层:
- Layer2(CUSUM):当 P(trending) > 0.5 时,微调 CUSUM 阈值(最多下调 10%),使拦截更灵敏
- 诊断日志:drift_mean、MAP_r、P(cp) 作为辅助信息输出,帮助理解拦截原因
6.3 日志示例
Layer0-BOCPD趋势机制: P(trending)=0.949>0.8 | drift=-0.003821 MAP_r=1 P(cp)=0.050
解读:
- P(trending)=0.949:94.9% 概率处于趋势状态,超过 80% 阈值 → 拦截
- drift=-0.003821:概率加权漂移为 -0.38%/K线,方向为下跌
- MAP_r=1:最可能的 run length 为 1,刚发生变点
- P(cp)=0.050:当前 K 线是变点的概率为 5%(等于先验,说明没有额外的变点信号)
7. 参数配置
| 参数 | 默认值 | 含义 |
|---|---|---|
| hazard_rate | 0.05 | 变点先验概率(平均 20 根 K 线一个变点) |
| mu0 | 0.0 | 均值先验(无趋势假设) |
| kappa0 | 1.0 | 先验精度(等价于 1 个虚拟观测) |
| alpha0 | 3.0 | 方差先验自由度 |
| beta0 | 5e-5 | 方差先验 scale |
| max_run | 60 | 最大 run length(约 5 小时) |
| drift_threshold | 0.0005 | 有经济意义的最小漂移(0.05%/5min) |
| bocpd_trend_thresh | 0.8 | P(trending) 拦截阈值 |
| 预热要求 | 20 根 K 线 | 约 100 分钟后才开始输出判断 |
8. 算法特点总结
| 特性 | 说明 |
|---|---|
| 在线更新 | 每根 K 线 O(R) 复杂度,R=60,适合实时场景 |
| 不确定性建模 | 同时维护所有可能的 run length,不做硬判断 |
| 自适应 | 数据少时后验宽(保守),数据多时后验窄(自信) |
| 概率输出 | 输出的是概率而非二值判断,方便与其他层级组合 |
| 共轭先验 | NIG-Student-t 共轭关系使更新有解析解,无需采样 |