为了帮您彻底理清“残差的计算”和“如何对残差进行测试”,我们用 R 语言来亲手模拟一组可口可乐(Coke)和百事可乐(Pepsi)的数据。
在量化金融中,这种模拟最迷人的地方在于:我们可以像上帝一样,主动在数据中埋入一条“橡皮筋”(协整关系),然后再通过两步法把它验证出来。
整体思路:采用==Engle-Granger==两步法:
我们需要 urca 包或 tseries 包来进行 ADF
检验。这里我们使用最专业的 urca 包。
我们要制造两个非平稳的价格序列,但它们之间有一个固定的长期关系:\(Coke = 10 + 1.5 \times Pepsi + 误差\)。
n <- 250 # 模拟 250 个交易日(大约一年的数据)
# 1. 模拟百事可乐 (Pepsi) 的价格:让它像无头苍蝇一样随机游走 (Non-stationary, I(1))
pepsi_returns <- rnorm(n, mean = 0, sd = 1) # 每日涨跌幅
pepsi <- 50 + cumsum(pepsi_returns) # 从50元开始累加,形成股票价格
# 2. 模拟一个【平稳的长期误差】(Stationary Error, I(0))
# 这就是连接两者的“橡皮筋”,它会围绕 0 上下波动,但绝不跑远
true_error <- arima.sim(model = list(ar = 0.5), n = n) * 2 # 一个自回归平稳序列
# 3. 根据长期关系,生成可口可乐 (Coke) 的价格
coke <- 10 + 1.5 * pepsi + true_error
# 把它们画出来看看
# Use english only in subtitles
plot(coke, type="l", col="red", ylim=c(min(pepsi), max(coke)),
main="Coke and Pepsi's price Simulation", xlab="Date", ylab="Price")
lines(pepsi, col="blue")
legend("topleft", legend=c("Coke", "Pepsi"), col=c("red", "blue"), lty=1)运行到这里,你会看到两根线虽然都在波动,但步调极其一致。这就是协整。
现在我们假装不知道上帝公式,只拿到了 coke 和
pepsi 的价格数据。
我们用普通的最小二乘法(OLS)让系统自己去寻找那条“最拟合的线”。
##
## Call:
## lm(formula = coke ~ pepsi)
##
## Residuals:
## Min 1Q Median 3Q Max
## -6.1755 -1.4689 -0.0553 1.8594 6.9669
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 7.22003 1.36817 5.277 0.000000286 ***
## pepsi 1.56373 0.02909 53.761 < 0.0000000000000002 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.404 on 248 degrees of freedom
## Multiple R-squared: 0.921, Adjusted R-squared: 0.9207
## F-statistic: 2890 on 1 and 248 DF, p-value: < 0.00000000000000022
在回归输出中,你会发现系统的估计非常接近我们的上帝设置(截距项接近
10,pepsi 的系数接近 1.5)。
【核心:残差是怎么计算出来的?】
残差(Residuals)就是“实际观察到的可口可乐价格”减去“模型预测的可口可乐价格”。
在 R 中,我们可以直接用 residuals() 函数提取它:
# 手动/自动计算残差
my_residuals <- residuals(model)
# 让我们画出这个残差图
plot(my_residuals, type="l", col="purple", main="两步法提取出的残差序列",
xlab="时间", ylab="残差值")
abline(h=0, col="black", lty=2) # 画一条 0 刻度线解释残差图: 你会发现这个残差极其规律,它虽然在上下跳动,但永远不会离 0 轴太远,只要涨高了就会跌回来,跌深了就会涨上去(均值回归)。这就说明这根“橡皮筋”是存在的。
虽然肉眼看它是平稳的,但考试和学术需要严格的统计检验。我们对刚才提取出来的
my_residuals 运行 ADF 检验。
# 对残差进行单位根检验 (ADF test)
# selectlags="AIC" 会自动选择最佳的滞后期
adf_result <- ur.df(my_residuals, type = "none", selectlags = "AIC")
# 查看检验报告
summary(adf_result)##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression none
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 - 1 + z.diff.lag)
##
## Residuals:
## Min 1Q Median 3Q Max
## -5.0355 -1.5682 0.1876 1.5156 6.1824
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## z.lag.1 -0.56013 0.06551 -8.550 0.00000000000000132 ***
## z.diff.lag 0.05744 0.06372 0.902 0.368
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 2.126 on 246 degrees of freedom
## Multiple R-squared: 0.2673, Adjusted R-squared: 0.2614
## F-statistic: 44.88 on 2 and 246 DF, p-value: < 0.00000000000000022
##
##
## Value of test-statistic is: -8.5501
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau1 -2.58 -1.95 -1.62
运行完上面最后一行代码后,控制台会输出一个报告。我们要找的是以下两个核心数据:
-5.24(或者其他比较大的负数)。1pct: -2.58,
5pct: -1.95, 10pct: -1.62。⚠️ 注意(考试/实践避坑):
刚才提到过,因为这里的残差是“估计出来的”,ur.df
输出的普通 DF 临界值(如
-2.58)会过于宽松。严格意义上,我们必须人工去对比
Engle-Granger 专用麦金农(MacKinnon)临界值表。 对于 250
个样本、2 个变量的情况:
我们将测试统计量(-5.24)与专用临界值(-3.37)进行对比: