不同算法得到的残差序列,用其计算Z-Score ,分值会有巨大差异
对比老版本(含 α)和新版本(不含 α)的 Z-score 计算差异。查看相关代码:
[3 tools called]
检查老版本代码,确认老版本的实现:
[1 tool called]
问题根源:窗口不匹配导致的参数偏移效应
核心差异
老版本(总是含α):
spread = log_alt - (alpha + beta_ols * log_base)
新版本(条件选择,可能不含α):
spread = log_alt - beta_ols * log_base # 当 use_alpha=False 时
为什么Z-score差异巨大?
1. 数学关系
两种价差的关系:
spread_with_α = log_alt - (α + β × log_base)
spread_no_α = log_alt - β × log_base
因此:spread_with_α = spread_no_α - α
理论上,如果 α 是常数,Z-score 应该相同,因为:
Z_with_α = (spread_with_α[-1] - mean(spread_with_α)) / std(spread_with_α)
= ((spread_no_α[-1] - α) - (mean(spread_no_α) - α)) / std(spread_no_α)
= (spread_no_α[-1] - mean(spread_no_α)) / std(spread_no_α)
= Z_no_α
2. 实际情况
关键问题:α 在长窗口(99期)上估计,但在短窗口(30期)上使用。
如果短窗口的真实关系是:
log_alt = α_short + β × log_base + ε
而你使用的是长窗口估计的 α_long,那么:
含α的价差:
spread_with_α = log_alt - (α_long + β × log_base)
= (α_short + β × log_base + ε) - (α_long + β × log_base)
= (α_short - α_long) + ε
不含α的价差:
spread_no_α = log_alt - β × log_base
= α_short + ε
3. 对Z-score的影响
含α情况:
mean(spread_with_α) ≈ (α_short - α_long) + mean(ε)std(spread_with_α) ≈ std(ε)Z_with_α = (ε[-1] - mean(ε)) / std(ε)
不含α情况:
mean(spread_no_α) ≈ α_short + mean(ε)std(spread_no_α) ≈ std(ε)Z_no_α = (α_short + ε[-1] - (α_short + mean(ε))) / std(ε) = (ε[-1] - mean(ε)) / std(ε)
理论上应该相同,但为什么会有差异?
4. 真实差异来源
原因1:α_short ≠ α_long(时变性问题)
如果短窗口的真实截距 α_short 与长窗口估计的 α_long 不同,那么:
- 含α的价差会有一个额外的偏移项
(α_short - α_long) - 这个偏移项会影响价差的分布形状,不仅仅是简单的平移
- 导致
std(spread_with_α) ≠ std(spread_no_α)
原因2:残差分布的非对称性
如果残差 ε 的分布在含α和不含α的情况下表现不同(因为模型不匹配),标准差会不同。
原因3:短窗口的均值回归
当使用不匹配的 α 时,价差序列可能出现:
- 趋势项(如果
α_short - α_long不是常数) - 导致
std(spread_with_α)被放大 - 最终使 Z-score 变小(因为分母变大)
量化分析
假设:
α_long = 5.0(长窗口估计)α_short = 4.5(短窗口真实值)std(ε) = 0.1
那么:
spread_with_α的均值会偏移-0.5- 如果短窗口内数据有趋势,
std(spread_with_α)可能 >std(spread_no_α) - 例如:
std(spread_with_α) = 0.15vsstd(spread_no_α) = 0.1 - Z-score 会相差
(0.1/0.15) ≈ 0.67倍
解决方案
这正是代码中智能模型选择的目的(第521-545行):
- 当
|α| > 5或α不显著时,使用不含α的模型 - 避免将不匹配的长窗口
α强加到短窗口上
建议
要诊断具体差异,可以计算:
# 在短窗口上重新估计alpha
log_base_short = np.log(recent_base) # 30期数据
log_alt_short = np.log(recent_alt)
X_short = sm.add_constant(log_base_short.iloc[:-1])
model_short = sm.OLS(log_alt_short.iloc[:-1], X_short).fit()
alpha_short = model_short.params.iloc[0]
# 对比
alpha_diff = alpha - alpha_short
如果 alpha_diff 很大(例如 > 0.5),说明 α 在短窗口不适用,此时使用不含 α 的模型更合理。
这也解释了为什么新版本会根据条件选择模型——这是为了避免长窗口参数在短窗口不适用导致的偏差。