###########################################################################
# Advanced Econometrics #
# Spring semester #
# dr Marcin Chlebus, dr Rafał Woźniak #
# University of Warsaw, Faculty of Economic Sciences #
# #
# Materials based on dr Piotr Wojcik Time Series Analysis for QF #
# #
# Lab 10: Stationarity testing #
# #
###########################################################################
# We start with defining path to current working directory
# setwd("C:\\Users\\asus\\Dysk Google\\WNE Przedmioty\\ADVANCED ECONOMETRICS\\2020\\Lab\\AE_Lab_10")
# install and load needed libraries
# install.packages("tseries")
# install.packages("urca")
# install.packages("fUnitRoots")
library(xts)
library(lmtest)
library(tseries)
library(urca)
library(fUnitRoots)
options(scipen = 999)
Sys.setenv(LANG = "en")###################################################
# 1. Differencing of non-stationary time series
# testing order of integration - ADF test
###################################################
# lets load daily data for SP500
SP500 <- read.csv("SP500.txt",
sep = ",",
dec = ".",
header = T,
stringsAsFactors = FALSE
)
head(SP500)## Name Date Open High Low Close Volume
## 1 SP500 19700102 92.06 93.54 91.79 93.00 0
## 2 SP500 19700105 93.00 94.25 92.53 93.46 0
## 3 SP500 19700106 93.46 93.81 92.13 92.82 0
## 4 SP500 19700107 92.82 93.38 91.93 92.63 0
## 5 SP500 19700108 92.63 93.47 91.99 92.68 0
## 6 SP500 19700109 92.68 93.25 91.82 92.40 0
## Name Date Open High Low Close Volume
## 11902 SP500 20170306 2375.23 2378.80 2367.98 2375.31 0
## 11903 SP500 20170307 2370.74 2375.12 2365.51 2368.39 0
## 11904 SP500 20170308 2369.81 2373.09 2361.01 2362.98 0
## 11905 SP500 20170309 2363.49 2369.08 2354.54 2364.87 0
## 11906 SP500 20170310 2372.52 2376.86 2363.04 2372.60 0
## 11907 SP500 20170313 2371.56 2374.42 2368.52 2373.47 0
# lets convert dates into format understood by R as date
SP500$Date <- as.Date(as.character(SP500$Date), "%Y%m%d")
head(SP500)## Name Date Open High Low Close Volume
## 1 SP500 1970-01-02 92.06 93.54 91.79 93.00 0
## 2 SP500 1970-01-05 93.00 94.25 92.53 93.46 0
## 3 SP500 1970-01-06 93.46 93.81 92.13 92.82 0
## 4 SP500 1970-01-07 92.82 93.38 91.93 92.63 0
## 5 SP500 1970-01-08 92.63 93.47 91.99 92.68 0
## 6 SP500 1970-01-09 92.68 93.25 91.82 92.40 0
# lets select just close price into the xts object
SP500 <- xts(SP500$Close, order.by = SP500$Date)
head(SP500)## [,1]
## 1970-01-02 93.00
## 1970-01-05 93.46
## 1970-01-06 92.82
## 1970-01-07 92.63
## 1970-01-08 92.68
## 1970-01-09 92.40
# and assign a name to the column with a close price into SP500
names(SP500)[1] <- "SP500"
head(SP500)## SP500
## 1970-01-02 93.00
## 1970-01-05 93.46
## 1970-01-06 92.82
## 1970-01-07 92.63
## 1970-01-08 92.68
## 1970-01-09 92.40
# To make it easier the above steps have been put
# into a function import_data_into_xts() stored
# in the file "function_import_data_into_xts.R"
# lets load it
source("function_import_data_into_xts.R")
# The function assumes that the data is stored in
# the subdirectory called "data".
# It requires just one argument, which is the name
# of the file (without .txt extension)# lets import SP500 data again
# we remove the created object
rm(SP500)
# and import it with the function
SP500 <- import_data_into_xts("SP500")
head(SP500)## SP500
## 1970-01-02 93.00
## 1970-01-05 93.46
## 1970-01-06 92.82
## 1970-01-07 92.63
## 1970-01-08 92.68
## 1970-01-09 92.40
## [1] "xts" "zoo"
# lets limit our data to days since the beginning of 2000
# it is easy and fast for xts objects:
# we put limiting dates into brackets:
# ["start_date_or_just_year/end_date_or_just_year"]
# One of the end can be skipped if one puts a limit
# only on one side
# for examples see here:
# http://stackoverflow.com/questions/11871572/subsetting-tricks-for-xts-in-r
# 作用:从原始数据集中提取从 2000 年 1 月 1 日开始直到最新的所有数据。
SP500 <- SP500["2000/", ]
head(SP500)## SP500
## 2000-01-03 1455.22
## 2000-01-04 1399.42
## 2000-01-05 1402.11
## 2000-01-06 1403.45
## 2000-01-07 1441.47
## 2000-01-10 1457.60
与 ADF 区别:DF 里假设残差项里没有自相关.
# First, we will conduct ADF test using R function ur.df()
# the test can be applied either to
# DF test
df.test <- ur.df(SP500$SP500, # vector tested
type = c("drift"), # constant deterministic ; c("none", "drift", "trend");
# component (variant 2 of the test)
lags = 0
) # lags for augmentation of ADF part; Number of lags for endogenous variable to be included.
summary(df.test)##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression drift
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 + 1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -107.065 -7.128 0.465 7.718 103.911
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.23226186 0.88547524 0.262 0.793
## z.lag.1 -0.00001436 0.00061695 -0.023 0.981
##
## Residual standard error: 15.11 on 4322 degrees of freedom
## Multiple R-squared: 1.253e-07, Adjusted R-squared: -0.0002312
## F-statistic: 0.0005416 on 1 and 4322 DF, p-value: 0.9814
##
##
## Value of test-statistic is: -0.0233 0.4271
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78
Intercept z.lag.1
they are: ==non interpretable==
在 urca 包的 ur.df 函数中,无论你选择哪种类型(none, drift, 或 trend):
这段代码执行的是金融时间序列分析中极其重要的一步:单位根检验(Unit Root Test)。它的目的是判断标普 500 指数是否是“平稳”的。
这段代码使用了 urca 包中的 ur.df()
函数。
SP500$SP500:测试对象。即标普 500
指数的点位数据。type = "drift":模型类型。
时间序列模型通常有三种:纯随机游走(none)、带漂移项(Drift,即有常数截距)、带趋势项(Trend,即随时间线性增长)。
这里选择 drift
是假设股市虽然波动,但可能存在一个基本的常数增长背景。
| 选项 | 包含成分 | 对应模型 (Model Type) | 常见视觉特征 |
|---|---|---|---|
| “none” | 无 | 纯随机游走 | 围绕 0 轴波动 |
| “drift” | 截距 (Intercept) | 带漂移随机游走 | 围绕非零均值波动 |
| “trend” | 截距 + 时间趋势 | 带趋势随机游走 | 随时间有明显线性偏斜 |
lags = 0:滞后阶数。
summary(df.test):打印详细的统计报告,告诉我们检验的具体结果。代码中的注释解释了统计学的术语:
vector tested:被检测的一串数字。constant deterministic component:确定性常数部分。简单说就是假设数据里包含一个==不随时间改变的“底数”==。variant 2 of the test:这是 DF
检验的第二种变体(带常数项,不带时间趋势)。要看懂这个复杂的表格,你只需要盯住两个关键点:
输出显示:Value of test-statistic is: -0.0233 0.4271
-0.0233 对应的是
tau2(即检验平稳性的 t 统计量)。0.4271 对应的是
phi1(检验常数项是否显著)。我们需要将统计量与底部的临界值表进行对比。
test-statistic
小于 临界值,则拒绝原假设(即序列是平稳的)。-0.0233 远远
大于 5% 水平下的 -2.86。标普 500 指数是不平稳的(存在单位根)。
-0.0233
没能闯过任何一个临界值的关卡(甚至连 10% 的阈值 -2.57 都没达到)。小贴士:
Pr(>|t|)里的0.981也印证了这一点——由于 p 值非常大,我们无法拒绝“存在单位根(不平稳)”的说法。
# tau statistic (-0.0233) is higher than the 5% critical value (-2.86)
# so we cannot reject the null about non-stationarity of SP500
# to be sure that conlusions may be drawn we need to check wheter there is no autocorrelation in residuals
resids_ <- as.data.frame(df.test@testreg$residuals)
colnames(resids_) <- "res"
bgtest(res ~ 1, data = resids_, order = 1)##
## Breusch-Godfrey test for serial correlation of order up to 1
##
## data: res ~ 1
## LM test = 17.14, df = 1, p-value = 0.00003472
这段代码是对之前的单位根检验(DF Test)结果进行稳健性检查 (Robustness Check),主要关注残差项的自相关问题。
| 代码行 | 功能解释 |
|---|---|
resids_ <- as.data.frame(df.test@testreg$residuals) |
从 ur.df 的结果对象(S4
对象)中提取残差 (Residuals)。@testreg
访问的是底层的回归模型。 |
colnames(resids_)<-"res" |
将残差列命名为 “res”,方便后续在公式中引用。 |
bgtest(res ~ 1, data = resids_, order = 1) |
执行 Breusch-Godfrey 检验(也称为 LM 检验),用于检测残差中是否存在序列相关 (Serial Correlation)。 |
针对 bgtest() 函数:
res ~ 1:
检验公式。因为我们是直接对残差本身进行检验,所以公式只有截距项(Constant)。data = resids_:
指定包含残差数据的数据框。order = 1: 指定检验的滞后阶数
(Order of Lags)。这里设置为 1,表示检查是否存在
一阶自相关 (AR(1))。输出显示 p-value = 3.472e-05:
代码中的注释揭示了计量分析中的一个核心矛盾:
单位根结论: >
tau statistic (-0.0233) is higher than the 5% critical value (-2.86)
由于 \(-0.0233 >
-2.86\)(落在非拒绝域),我们无法拒绝原假设,认为
SP500 序列具有单位根 (Unit Root),即非平稳
(Non-stationary)。
问题的关键: >
to be sure that conclusions may be drawn... check whether there is no autocorrelation in residuals
Dickey-Fuller (DF)
检验的一个前提假设是残差项必须是白噪声 (White
Noise)。如果残差中存在自相关(如 BG 检验所示),那么 DF
检验的统计量就不再有效,结论可能产生偏差。
由于你的 BG 检验结果显示存在显著的自相关,这意味着你之前使用的
lags = 0 的 DF 检验是不充分的。
改进方案: 你应该增加滞后项,改用 增广迪基-福勒检验 (Augmented Dickey-Fuller Test, ADF)。
ur.df() 中尝试增加 lags 参数(例如使用
lags = 1 或通过信息准则自动选择
selectlags = "AIC")。bgtest 的 \(p\) 值大于 \(0.05\),从而确保残差项不再有序列相关。~ (Tilde/Formula Operator):
可以读作“由…决定”或“关于…的函数”。它将变量分为两部分:
1 (The Intercept/Constant): 在 R
的模型语法中,数字 1 特指截距项
(Intercept),也就是数学公式中的常数项 \(\beta_0\)。| R 公式 | 数学含义 (English Term) | 说明 |
|---|---|---|
y ~ x |
\(y = \beta_0 + \beta_1x + \varepsilon\) | 简单线性回归 (Simple Linear Regression) |
y ~ 1 |
\(y = \beta_0 + \varepsilon\) | 仅截距模型 (Intercept-only Model) |
y ~ 0 + x |
\(y = \beta_1x + \varepsilon\) | 过原点的回归 (Regression through the Origin) |
y ~ x1 + x2 |
\(y = \beta_0 + \beta_1x_1 + \beta_2x_2 + \varepsilon\) | 多元线性回归 (Multiple Linear Regression) |
bgtest, order = 2##
## Breusch-Godfrey test for serial correlation of order up to 2
##
## data: res ~ 1
## LM test = 25.994, df = 2, p-value = 0.000002267
这次检验是针对残差是否存在二阶序列相关 (Second-order Serial Correlation) 进行的测试。
res ~ 1: 检验目标。表示对残差序列
res 本身进行建模(仅包含截距项/均值)。order = 2:
滞后阶数。这意味着检验不仅考虑上一期 (\(t-1\)) 的影响,还考虑上上期 (\(t-2\))
的影响。它会检查残差是否受到过去两个时点数值的显著影响。order = 2)。由于 \(p < 0.05\),我们拒绝原假设 (\(H_0\): 无序列相关)。
简单一句话总结:
即使考虑了两个滞后阶数,残差中依然存在显著的序列相关 (Serial
Correlation)。这意味着之前的单位根检验模型(lags = 0)未能提取出数据中所有的系统性信息,其结论依然是不可靠的。
##
## Breusch-Godfrey test for serial correlation of order up to 3
##
## data: res ~ 1
## LM test = 26.151, df = 3, p-value = 0.000008868
##
## Breusch-Godfrey test for serial correlation of order up to 4
##
## data: res ~ 1
## LM test = 27.118, df = 4, p-value = 0.00001882
##
## Breusch-Godfrey test for serial correlation of order up to 5
##
## data: res ~ 1
## LM test = 31.553, df = 5, p-value = 0.000007283
结论:上述测试不合适。inaaprropreate.
通过对 order = 1 到 order = 5 的
Breusch-Godfrey (BG)
检验结果进行对比,我们可以得出以下系统性的结论:
| 滞后阶数 (Order) | LM 统计量 | 自由度 (df) | P 值 (p-value) | 结论 (Conclusion) |
|---|---|---|---|---|
| 1 | 17.14 | 1 | \(3.47 \times 10^{-5}\) | 拒绝 \(H_0\),存在自相关 |
| 2 | 25.99 | 2 | \(2.27 \times 10^{-6}\) | 拒绝 \(H_0\),存在自相关 |
| 3 | 26.15 | 3 | \(8.87 \times 10^{-6}\) | 拒绝 \(H_0\),存在自相关 |
| 4 | 27.12 | 4 | \(1.88 \times 10^{-5}\) | 拒绝 \(H_0\),存在自相关 |
| 5 | 31.55 | 5 | \(7.28 \times 10^{-6}\) | 拒绝 \(H_0\),存在自相关 |
所有阶数(1 到 5)的 \(p\) 值均远小于 0.05。这表明无论我们向后观察多少期,残差中都存在显著的序列相关性。数据并非“白噪声” (White Noise),仍有规律未被模型捕捉。
随着 order(滞后阶数)的增加,LM 统计量
总体呈上升趋势(从 17.14 升至
31.55)。这说明更高阶的滞后项对当前残差仍有解释力,模型遗漏的信息较为复杂。
ur.df(..., lags = 0) 是基于“残差独立同分布
(i.i.d.)”的假设。BG 检验的结果彻底推翻了这个假设。这意味着你之前得到的
tau 统计量和 \(p\)
值是不可信的 (Biased/Invalid)。既然残差“不干净”,为了获得可靠的单位根检验结论,你应该:
ur.df 函数中,通过调整 lags
参数来吸收残差中的自相关。ur.df 中使用 selectlags = "AIC" 或
"BIC"。这会让 R
自动尝试不同的滞后阶数,直到残差项接近白噪声为止。lags
之后,再次运行 bgtest 得到的 \(p\) 值大于 0.05
时,该单位根检验的结论才是稳健可靠的。ur.df# lets check ADF with 1 augmentation
# ADF test
adf.test <- ur.df(SP500$SP500,
type = c("drift"),
# selectlags = c("AIC")
lags = 1 # 这里从 1 改为 2,看看结果,并对比
)
summary(adf.test)##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression drift
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)
##
## Residuals:
## Min 1Q Median 3Q Max
## -106.814 -7.246 0.621 7.598 103.263
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.10719631 0.88305494 0.121 0.903
## z.lag.1 0.00009488 0.00061538 0.154 0.877
## z.diff.lag -0.06306960 0.01517228 -4.157 0.0000329 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15.06 on 4320 degrees of freedom
## Multiple R-squared: 0.003984, Adjusted R-squared: 0.003523
## F-statistic: 8.64 on 2 and 4320 DF, p-value: 0.00018
##
##
## Value of test-statistic is: 0.1542 0.5545
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78
在这段代码中,你执行了增广迪基-福勒检验 (Augmented Dickey-Fuller Test, ADF)。相比于之前的 DF 检验,它通过引入滞后差分项来解决残差自相关问题。
ur.df(..., type = "drift", lags = 1):
type = "drift":
模型包含截距项(常数项),适用于均值不为零但没有明显线性时间趋势的时间序列。lags = 1:
关键参数。在回归方程中加入了一阶滞后差分项 \(\Delta
y_{t-1}\)。其目的是吸收残差中的序列相关性,使残差项接近白噪声。summary 展示了 ADF
检验背后的底层的线性回归模型:lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)。
z.lag.1: 序列的一阶滞后水平值 (\(y_{t-1}\))。其系数即为我们检验单位根的核心对象。z.diff.lag: 序列的一阶滞后差分项
(\(\Delta y_{t-1}\))。
Pr(>|t|) 为
3.29e-05,带有三个星号 ***。lags = 0),残差中确实会遗漏重要的动态信息。在输出的底部,你会看到专门用于单位根判断的统计量:
Value of test-statistic is: 0.1542 0.5545:
tau2,用于检验是否存在单位根。phi1,这是一个复合假设检验(同时检验是否存在单位根且漂移项为
0)。tau2 的 5% 临界值:-2.86。如果你将 lags 从 1 改为 2,你会发现回归方程中会多出一项
z.diff.lag2 (\(\Delta
y_{t-2}\))。
lags
的增加,tau2 的值通常会发生微调。如果
z.diff.lag2 依然显著,说明需要更高阶的滞后。lags
的代价是损失自由度。如果增加 lags 后 tau2
依然远大于临界值,那么“序列非平稳”的结论将变得更加稳健。lags 是 1 还是
2,通常都会得到非平稳 (Non-stationary)
的结论,因为价格序列通常具有典型的随机游走特征。你注释掉的 selectlags = c("AIC")
实际上是更推荐的做法。手动尝试 lags = 1 或
lags = 2 属于探索性分析,而使用 AIC (Akaike
Information Criterion)
准则可以自动在“模型简洁性”与“残差白噪声化”之间寻找最佳平衡点。
ur.dfadf.test <- ur.df(SP500$SP500,
type = c("drift"),
# selectlags = c("AIC")
lags = 2 # 这里从 1 改为 2,看看结果,并对比
)
summary(adf.test)##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression drift
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)
##
## Residuals:
## Min 1Q Median 3Q Max
## -105.738 -7.228 0.745 7.722 99.840
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.0153446 0.8828755 0.017 0.98613
## z.lag.1 0.0001687 0.0006154 0.274 0.78395
## z.diff.lag1 -0.0660805 0.0152161 -4.343 0.0000144 ***
## z.diff.lag2 -0.0455295 0.0151906 -2.997 0.00274 **
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15.05 on 4318 degrees of freedom
## Multiple R-squared: 0.006047, Adjusted R-squared: 0.005356
## F-statistic: 8.756 on 3 and 4318 DF, p-value: 0.00000869
##
##
## Value of test-statistic is: 0.2742 0.6294
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78
adf.test <- ur.df(SP500$SP500,
type = c("drift"),
# selectlags = c("AIC")
lags = 3 # 这里从 1 改为 2,看看结果,并对比
)
summary(adf.test)##
## ###############################################
## # Augmented Dickey-Fuller Test Unit Root Test #
## ###############################################
##
## Test regression drift
##
##
## Call:
## lm(formula = z.diff ~ z.lag.1 + 1 + z.diff.lag)
##
## Residuals:
## Min 1Q Median 3Q Max
## -105.740 -7.212 0.735 7.745 99.733
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.002889 0.883594 0.003 0.99739
## z.lag.1 0.000179 0.000616 0.291 0.77138
## z.diff.lag1 -0.066377 0.015236 -4.356 0.0000135 ***
## z.diff.lag2 -0.046025 0.015253 -3.017 0.00256 **
## z.diff.lag3 -0.006240 0.015210 -0.410 0.68162
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15.05 on 4316 degrees of freedom
## Multiple R-squared: 0.006086, Adjusted R-squared: 0.005165
## F-statistic: 6.607 on 4 and 4316 DF, p-value: 0.00002685
##
##
## Value of test-statistic is: 0.2906 0.6418
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78
在这段代码中,你执行了增广迪基-福勒检验 (ADF),并将滞后阶数设置为 3。这是一种更为严谨的平稳性检测方法。
ur.df(..., type = "drift", lags = 3):
type = "drift":
模型包含截距项(Drift),用于检测序列是否在均值不为零的情况下具有单位根。lags = 3:
核心参数。这意味着在回归方程中加入了三阶滞后差分项(\(\Delta y_{t-1}, \Delta y_{t-2}, \Delta
y_{t-3}\))。其目的是通过这些滞后项吸收残差中的自相关,确保检验结果的稳健性。summary 展示了该检验背后的线性回归模型详情:
z.diff.lag1: 极显著
(***)。说明一阶滞后差分对当前变化有很强的解释力。z.diff.lag2: 显著
(**)。说明二阶滞后差分仍然包含有效信息。z.diff.lag3: 不显著
(p-value = 0.68162)。这提示我们,对于 SP500
这一序列,增加到 3 阶滞后可能已经“过头”了,2
阶滞后或许已经足够捕捉动态特征。z.lag.1: 这是我们==最关心的项==(\(y_{t-1}\))。其 \(t\) 统计量为
0.291,且不显著。这意味着==序列具有强烈的随机游走特征==。在输出底部,提供了用于最终决策的统计量和临界值:
Value of test-statistic is: 0.2906 0.6418:
tau2(单位根检验统计量)。phi1(联合检验统计量)。tau2 统计量
0.2906 远大于 5% 显著性水平下的临界值
-2.86。z.diff.lag
的显著性,你可以发现数据存在“记忆性”。前两天的价格变动对今天的变动有显著影响,但到第三天这种影响就消失了。z.diff.lag3
不显著,如果你追求模型的简洁性(Parsimony),可以考虑退回到
lags = 2。这正是 selectlags = "AIC"
自动优化的逻辑所在。我们可以把这个逻辑串成一个完整的诊断流程:
| 检查项 | 你的假设结果 | 翻译成“人话” |
|---|---|---|
| 滞后项显著性 | lag3 不显著 |
“大前天”的消息已经不影响今天了,没必要再往后看了。 |
| 残差检验 (BG) | \(p > 0.05\) | 仪器里没有“滋滋”的杂音了,测量结果现在很可靠。 |
| 单位根统计量 | tau2 < -2.86 |
统计结果显示:这只狗是被绳子拴住的,它虽然乱跑,但总会跑回来。 |
| 最终定论 | Stationary | 平稳序列。你可以基于均值去预测它的未来。 |
在现实的金融市场中,如果你在 SP500 的 价格 (Price)
序列上测出了 tau2 < -2.86,通常只有两种可能:
通常,我们会对价格取对数后做差分,得到 收益率 (Return)。收益率序列通常是平稳的(Stationary),而原始价格序列几乎永远是非平稳的(Non-stationary)。
结论:你的代码显示 tau
统计量(0.2906)远大于临界值(-2.86)。这意味着 SP500
就是那个醉汉,它的价格没有回归规律,是不可预测的非平稳序列。
我们在做单位根检验时,就像是用仪器测量醉汉。如果仪器本身“滋滋”响(残差自相关),那测量结果就不准。
为了让体检结果可靠,我们必须把这些噪音(之前的价格波动影响)处理掉。这就是你把
lags 从 1 改到 3 的原因。
bgtest# to be sure that conlusions may be drawn we need to check wheter there is no autocorrelation in residuals
resids_ <- as.data.frame(adf.test@testreg$residuals)
colnames(resids_) <- "res"
bgtest(res ~ 1, data = resids_, order = 1)##
## Breusch-Godfrey test for serial correlation of order up to 1
##
## data: res ~ 1
## LM test = 0.0000087635, df = 1, p-value = 0.9976
##
## Breusch-Godfrey test for serial correlation of order up to 2
##
## data: res ~ 1
## LM test = 0.0029482, df = 2, p-value = 0.9985
##
## Breusch-Godfrey test for serial correlation of order up to 3
##
## data: res ~ 1
## LM test = 0.0036146, df = 3, p-value = 0.9999
##
## Breusch-Godfrey test for serial correlation of order up to 4
##
## data: res ~ 1
## LM test = 1.2679, df = 4, p-value = 0.8668
##
## Breusch-Godfrey test for serial correlation of order up to 5
##
## data: res ~ 1
## LM test = 6.3139, df = 5, p-value = 0.2769
# tau statistic (0.1542) is higher than the 5% critical value (-2.86)
# so we cannot reject the null about non-stationarity of SP500
# but in fact we do not know which of the above tests is correct.
# Maybe we should add even more augmentations?order = 1 到 5:
这是你检查的深度。
order = 1:只看“昨天”的误差会不会影响今天。order = 5:一口气检查“过去五天”的误差组合起来会不会对今天产生系统性的干扰。看这一组 \(p\)
值:0.9976, 0.9985, 0.9999,
0.8668, 0.2769。
对比一下你之前的操作,逻辑进化如下:
order = 1, 2, 3)时,\(p\) 值几乎就是 1。这说明通过在 ADF
检验里加入 3
个滞后项,你已经把最明显的干扰规律给彻底吸收了。order = 5),虽然 \(p\) 值降到了
0.2769,但依然远高于
0.05。这说明更远的时间点也没有明显的干扰。这一组结果给了你底气。你可以非常有信心对手里的这份 SP500 分析报告签字:
testdf2# As an alternative, to perform ADF test we can use a function testdf()
# written by the lecturer and defined in the file function_testdf.R
# This approach has an advantage over ur.df() since it displays the
# values of the Breusch-Godfrey statistic that tests for autocorrelation
# of residuals in the testing equation. This gives us a hint, which
# number of augmentations to choose.
source("function_testdf2.R")# test.type = {"nc", "c", "ct"}
testdf2(
variable = SP500$SP500, # vector tested
test.type = "c", # test type
max.augmentations = 3, max.order = 2
) # maximum number of augmentations added## augmentations adf p_adf p_bg.p.value.1 p_bg.p.value.2
## 1 0 -0.02327215 0.9537731 0.00003471589 0.000002266769
## 2 1 0.15417877 0.9681014 0.84688579206 0.010672802337
## 3 2 0.27418797 0.9764016 0.98500157014 0.997153487580
## 4 3 0.29058538 0.9770663 0.99763800439 0.998526983558
| augmentations | adf | p_adf | bgodfrey.statistic | bgodfrey.statistic.1 | bgodfrey.statistic.2 | p_bg.p.value.1 | p_bg.p.value.2 |
|---|---|---|---|---|---|---|---|
| 0 | -0.02327215 | 0.9537731 | 4324 | 17.140403811619 | 25.994309992 | 0.00003471589 | 0.000002266769 |
| 1 | 0.15417877 | 0.9681014 | 4323 | 0.037285075608 | 9.080113222 | 0.84688579206 | 0.010672802337 |
| 2 | 0.27418797 | 0.9764016 | 4322 | 0.000353396812 | 0.005701143 | 0.98500157014 | 0.997153487580 |
| 3 | 0.29058538 | 0.9770663 | 4321 | 0.000008763535 | 0.002948205 | 0.99763800439 | 0.998526983558 |
Interpretation for Row 3 (Augmentations = 2): 对于第三行的解读
Model Diagnostics: At 2 augmentations, the
p-values of the Breusch-Godfrey test (p_bg) are 0.985 and
0.997, both significantly exceeding the 0.05 threshold. This indicates
that the residuals are free from serial correlation, confirming that the
model is well-specified and the ADF test results are valid.
Unit Root Test: The ADF test statistic is 0.274,
and the associated p-value (p_adf) is 0.976. Since the
p-value is greater than 0.05, we fail to reject the null hypothesis
(\(H_0\)) that the series has a unit
root.
Conclusion: Based on these results, we conclude that the SP500 series is non-stationary.
| 列名 | 中文名称 | 作用 | 原假设 (\(H_0\)) | 判定标准 (p值) |
|---|---|---|---|---|
augmentations |
滞后阶数 | 决定模型往回看多少期,用于消除残差自相关。 | – | 通常选择能使残差干净的最小值。 |
adf |
ADF 统计量 | 衡量序列是否存在单位根的数值。 | – | 负得越厉害,越倾向于平稳(通常结合p值看)。越大(接近于0或正值)则不平稳(有单位根) |
p_adf |
平稳性检验 p 值 | 【最终答案】 判断序列是否平稳。 | 序列不平稳 (存在单位根) | > 0.05:不平稳,有单位根
✅ < 0.05:平稳,无单位根❌ |
p_bg.p.value.X |
残差自相关 p 值 | 【质量门槛】 检查模型是否“干净”。 | 残差无自相关 (模型合格) | > 0.05:合格 ✅
(无自相关) < 0.05:不合格 ❌ (有噪音) |
| 关注点 | 重点内容 |
|---|---|
| 看表顺序 | 先看右边 (p_bg),再看左边
(p_adf)。
只有右边及格(>0.05)了,左边的结论才有意义。 |
| \(H_0\) 的区别 | 这是最容易混淆的: 1. ADF 的 \(H_0\) 是我们想拒绝的(不平稳)。 2. BG 的 \(H_0\) 是我们想接受的(模型合格)。 |
| 有效行判定 | 只要有一列 p_bg 小于
0.05,该行即为“无效模型”,应当舍弃,增加滞后项再看下一行。 |
| 科学计数法 | 看到 e-05 或 e-06
这种,在考试中直接视作 < 0.05。 |
快速记忆口诀:
# if you want to see the numbers in a traditional notation
# we can put a "penalty" on the scientific notation
options(scipen = 4)
testdf2(
variable = SP500$SP500, # vector tested
test.type = "c", # test type
max.augmentations = 3, # maximum number of augmentations added
max.order = 5
) # maximum order of residual lags for BG test## augmentations adf p_adf p_bg.p.value.1 p_bg.p.value.2
## 1 0 -0.02327215 0.9537731 0.00003471589 0.000002266769
## 2 1 0.15417877 0.9681014 0.84688579206 0.010672802337
## 3 2 0.27418797 0.9764016 0.98500157014 0.997153487580
## 4 3 0.29058538 0.9770663 0.99763800439 0.998526983558
## p_bg.p.value.3 p_bg.p.value.4 p_bg.p.value.5
## 1 0.000008867786 0.00001881998 0.000007282947
## 2 0.028005430973 0.03739800486 0.010565203655
## 3 0.979939791006 0.85021968490 0.273595879359
## 4 0.999942264345 0.86679589790 0.276860103570
# For no augmentations (row 1 with augmentations = 0)
# residuals are autocorrelated
# (BG test rejects H0 of no autocorrelation in residuals in all cases,
# i.e. for order 1 its p-value = 0.00003471589 <<< 0.05)
# Therefore we add one augmentation
# (see second row with augmentations = 1).
# This is enough NOT to reject LACK of autocorrelation of order 1
# (p_bg = 0.84688579206 >> 0.05)
# but for the rest orders p-values are below 5% significance level (however, above 1%)
# Two augmentations give us all p-values significantly above any reasonable significance level.
# p-values 0.98500157014 0.997153487580 0.979939791006 0.85021968490 0.273595879359
# As a result, we can see that the correct ADF statistic
# is equal 0.27418797
# It's p-value = 0.9764016, so the test does NOT reject
# H0 about NON-stationarity,
# so SP500 index is NOT stationary in the analyzed period# In the second stage we repeat the ADF test on the first differences
# of the SP500 index to check if SP500 is integrated of order 1 or higher.
# lets use testdf() function on the first differences of the SP500 index
testdf2(
variable = diff.xts(SP500$SP500),
test.type = "nc",
max.augmentations = 3, max.order = 5
)## augmentations adf p_adf p_bg.p.value.1 p_bg.p.value.2 p_bg.p.value.3
## 1 0 -70.11650 0.01 0.8365459 0.01089639 0.02855909
## 2 1 -50.16345 0.01 0.9718109 0.99565056 0.98142766
## 3 2 -40.10057 0.01 0.9835396 0.99737258 0.99985496
## 4 3 -34.68379 0.01 0.9254432 0.99563049 0.99907558
## p_bg.p.value.4 p_bg.p.value.5
## 1 0.03833001 0.01096834
## 2 0.85685770 0.28198170
## 3 0.87265328 0.28579545
## 4 0.99962913 0.34563228
# For no augmentations (row 1 with augmentations = 0)
# residuals are not autocorrelated on 1% alpha level
# (BG test does not reject H0 of no autocorrelation in residuals,
# order 1 p-value for BG test is p-value = 0.8474314 >> 0.05)
# For 1 augmentation (row 2 with augmentations = 1)
# residuals are not autocorrelated on all reasonable levels
# (BG test does not reject H0 of no autocorrelation in residuals,
# p-values = 0.9854562 0.99726832 0.98161385 0.85661534 0.281822275)
# Therefore the correct (A)DF statistic is equal -50.17631
# It's p-value < 0.01 (see warnings), so the test
# DOES reject H0 about non-stationarity,
# of the first differences of SP500 index.
# so dif(SP500) IS already STATIONARY
# Putting the results of the two above mentioned tests together:
# SP500 is NOT stationary
# dif(SP500) is stationary
# conclusion: SP500 is integrated of order 1在这里可以得出结论了:我们的数据是non-stationary. 通过解读dataframe的每一行。
ur.pp## PP 检验
# Phillips-Perron (PP) - similar to ADF, but with better power
# the null and alternative hypotheses are the same as in ADF
# H0: time series is not stationary (integrated of order >= 1)
# Ha: time series is stationary (integrated of order = 0)
pp.test <- ur.pp(SP500$SP500, # tested series
type = c("Z-tau"), # standardization of the test statistic
model = c("constant")
) # constant deterministic component
# which means we assume that any trends in the data are stochastic
summary(pp.test)##
## ##################################
## # Phillips-Perron Unit Root Test #
## ##################################
##
## Test regression with intercept
##
##
## Call:
## lm(formula = y ~ y.l1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -107.065 -7.128 0.465 7.718 103.911
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.2322619 0.8854752 0.262 0.793
## y.l1 0.9999856 0.0006169 1620.864 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15.11 on 4322 degrees of freedom
## Multiple R-squared: 0.9984, Adjusted R-squared: 0.9984
## F-statistic: 2.627e+06 on 1 and 4322 DF, p-value: < 2.2e-16
##
##
## Value of test-statistic, type: Z-tau is: 0.363
##
## aux. Z statistics
## Z-tau-mu -0.073
##
## Critical values for Z statistics:
## 1pct 5pct 10pct
## critical values -3.434889 -2.862734 -2.567433
# Value of the test-statistic Z-tau (0.363) is higher
# than the 5% critical value (-2.862734)
# so we CANNOT reject the null about non-stationarity of SP500这段代码展示了 Phillips-Perron (PP) 检验的结果,这是计量经济学中判断时间序列是否“平稳”的常用工具。
以下是针对代码、参数及输出结果的通俗解读:
ur.pp(...): 这是执行 PP
检验的主函数。SP500$SP500:
被检测的数据。这里使用的是标普 500
指数的原始价格序列。type = "Z-tau":
指定统计量的类型。这是一种标准化的计算方法,使其结果在解读上与 ADF
检验的 t 统计量非常相似。model = "constant":
模型设定。这里假设数据中包含一个截距项(常数项)。这意味着我们承认数据可能有一个起始水平,但假设它随时间变化的趋势是==随机的(Stochastic)==,而不是像时钟一样精准运动的(Deterministic)。| 参数 (Parameter) | 选项 (Option) | 中文/英文含义 | 解释 |
|---|---|---|---|
type |
Z-alpha |
系数统计量 (Coefficient-based) | 基于回归系数的归一化,类似于 ADF 中的无截距项情况。 |
Z-tau |
t 统计量 (t-statistic based) | 更常用。基于 t 检验统计量的渐近分布,直观性更强。 | |
model |
constant |
截距模型 (Constant/Intercept) | 假设序列有非零均值,但没有长期趋势。 |
trend |
趋势模型 (Trend) | 假设序列包含一个随时间变化的线性趋势项。如果
S&P 500 图形呈现出长期向上的走势,你应该使用
model = "trend"。这能更好地控制趋势对单位根检验的干扰。 |
model:constant vs trend这是决定检验有效性的关键,取决于数据的视觉特征:
constant (截距项):
trend (截距 + 时间趋势):
constant 模型,检验的功效 (Power)
会大幅下降,容易出现“虚假非平稳”(即明明序列是趋势平稳的,却因模型漏掉了趋势项而无法拒绝非平稳的原假设)。在 PP 检验中,你注释里提到的“假设任何趋势都是随机的 (stochastic trends)”,实际上是说该检验对异方差和自相关(Autocorrelation)具有稳健性(Robust)。PP 检验通过==对统计量进行修正==,使得它==不需要==像 ADF 检验那样人为地通过==增加滞后项(lags)==来处理序列相关,这是 PP 检验相比 ADF 的==主要优势==之一。
y.l1 的估计值约为 0.9999。这非常接近
1,在直觉上暗示了这是一个“随机游走”过程,即昨天的价格几乎决定了今天的价格。1. 到底在测什么? 这个测试在问一个问题:标普 500 的价格序列是“安分的”还是“浪荡的”?
2. 结果怎么看?
3. 结论是什么?
4. 接下来该怎么办? 因为数据不平稳,你不能直接把这个价格序列放进普通的回归模型里,否则会产生“伪回归”(看起来很有道理其实全是扯淡的关系)。
# lets test SP500's first differences
pp.test.d <- ur.pp(diff.xts(SP500$SP500),
type = c("Z-tau"),
model = c("constant")
) # constant deterministic component
summary(pp.test.d)##
## ##################################
## # Phillips-Perron Unit Root Test #
## ##################################
##
## Test regression with intercept
##
##
## Call:
## lm(formula = y ~ y.l1)
##
## Residuals:
## Min 1Q Median 3Q Max
## -106.831 -7.244 0.629 7.595 103.217
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.23868 0.22909 1.042 0.298
## y.l1 -0.06298 0.01516 -4.155 0.0000332 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 15.06 on 4321 degrees of freedom
## Multiple R-squared: 0.003979, Adjusted R-squared: 0.003748
## F-statistic: 17.26 on 1 and 4321 DF, p-value: 0.00003323
##
##
## Value of test-statistic, type: Z-tau is: -70.7898
##
## aux. Z statistics
## Z-tau-mu 1.0513
##
## Critical values for Z statistics:
## 1pct 5pct 10pct
## critical values -3.434889 -2.862734 -2.567433
# summary(pp.test.d) # <- original
# WHY?
# Value of the test-statistic Z-tau (-70.7898) is lower than
# the 5% critical value (-2.862734)
# so we reject the null about non-stationarity
# of SP500's first differences
# so again finally SP500 ~ I(1)这段代码展示了 Phillips-Perron (PP) 检验,它是除了 ADF 之外另一种常用的==单位根检验方法==。
ur.pp(): 执行 Phillips-Perron
(PP) 检验 的函数。相比 ADF
检验==通过增加滞后项==(Augmentations)来处理残差自相关,PP
检验使用==非参数==方法来校正统计量,对异方差性(Heteroskedasticity)==更具稳健性==。diff.xts(SP500$SP500):
type = "Z-tau":
指定统计量类型。Z-tau 对应于 t
统计量版本(最常用);另一种是
Z-rho,对应于回归系数版本。model = "constant":
这是理解时间序列单整性(Integration)的关键。
| 比较项 | ur.pp(diff.xts(SP500$SP500), ...) |
ur.pp(SP500$SP500, ...) |
|---|---|---|
| 测试对象 | 一阶差分 (First Difference) | 水平值 (Level) |
| 经济含义 | 价格的变化/收益率 | 价格的绝对数值 |
| 你的结果 | 平稳 (Stationary) | 不平稳 (Non-stationary) |
| 结论含义 | 证明序列是 \(I(1)\) | 证明序列不是 \(I(0)\) |
通俗解读:
SP500$SP500 (原始价格)
时,你是在问:“标普500的价格会回落到一个固定均值吗?” 答案通常是
No(它有增长趋势,不平稳)。diff.xts(...) (价格变动)
时,你是在问:“标普500每天涨跌的幅度是否稳定在某个范围内?” 答案通常是
Yes(平稳)。Q: 为什么我们要同时做这两个测试?
A (Chinese): 通过对比原始序列(Level)和一阶差分序列(First Difference)的结果,我们可以确定序列的单整阶数。如果原始序列不平稳而一阶差分后平稳,说明该序列是 \(I(1)\)(一阶单整)。这在建模(如构建 ARIMA 或协整检验)前是必须的步骤,因为直接对非平稳序列进行回归会导致“伪回归”(Spurious Regression)。
A (English): By comparing the results of the Level series and the First Difference series, we can determine the order of integration. If the level is non-stationary but the first difference is stationary, the series is Integrated of order 1, or \(I(1)\). This step is crucial before modeling (e.g., ARIMA or Cointegration) to avoid Spurious Regression, which occurs when non-stationary variables appear to be related simply because they both have time trends.
备注: 你的 PP 统计量为 -70.78,这比之前 ADF 注释里的 -50 还要“猛”,说明差分后的平稳性极其显著,没有任何争议。
ur.kpss# KPSS
# In KPSS test the null and alternative hypotheses are reversed
# as compared to ADF and PP
# KPSS
# H0: time series IS stationary (integrated of order = 0)
# Ha: time series is stationary (integrated of order >= 1)
# In KPSS if the test statistic is higher than the critical value,
# we reject the null hypothesis and when test statistic is lower
# than the critical value, we cannot reject the null hypothesis.
kpss.test <- ur.kpss(SP500$SP500,
type = c("mu")
) # constant deterministic component
summary(kpss.test)##
## #######################
## # KPSS Unit Root Test #
## #######################
##
## Test is of type: mu with 10 lags.
##
## Value of test-statistic is: 21.8263
##
## Critical value for a significance level of:
## 10pct 5pct 2.5pct 1pct
## critical values 0.347 0.463 0.574 0.739
# the KPSS test statistic (21.8263) is higher than
# the 5% critical value (0.463)
# so we reject the null about STATIONARITY of SP500KPSS 检验在时间序列分析中扮演着“==反向验证者==”的角色。在考试中,最关键的是不要把它的原假设和 ADF/PP 搞混。
以下是详细的代码、参数及结果解读:
ur.kpss(): 执行 KPSS
检验 的函数。SP500$SP500:
被测试的原始序列(水平值 Level)。type = "mu":
mu
是默认选项,适用于大多数情况,尤其是当你怀疑数据可能有一个固定的均值时。mu
是希腊字母 \(\mu\)
的英文拼写,它代表的是 均值 (Mean) 或 截距项
(Intercept/Constant)。当你设定 type = “mu”
时,你是在告诉模型:“假设该序列围绕一个常数均值平稳”。在数学表达上,这对应于以下回归模型:\(Y_t = \mu + \varepsilon_t\)type = "tau",用于检验趋势平稳
(Trend
Stationarity),即序列是否围绕一个随时间变化的趋势线平稳。tau
对应希腊字母 \(\tau\)
(Tau)。在某些计量经济学文献中,\(\tau\)
有时用来表示包含时间趋势的项。设定为 tau 时,模型变为:\(Y_t = \mu + \beta t + \varepsilon_t\)这是 KPSS 最容易丢分的地方。请牢记以下对照:
| 特性 | ADF / PP 检验 | KPSS 检验 |
|---|---|---|
| 原假设 (\(H_0\)) | 非平稳 (有单位根 \(I(1)\)) | 平稳 (无单位根 \(I(0)\)) |
| 备择假设 (\(H_a\)) | 平稳 (\(I(0)\)) | 非平稳 (\(I(1)\)) |
| 判定逻辑 | \(p < 0.05\) 推翻“坏结果”,得到“平稳” | 统计量 > 临界值 推翻“好结果”,得到“不平稳” |
| 英文 (English) | 中文 (Chinese) |
|---|---|
| Null Hypothesis (\(H_0\)) | 原假设 / 零假设 |
| Alternative Hypothesis (\(H_a\)) | 备择假设 |
| Level Stationarity | 均值平稳 / 水平平稳 |
| Critical Value | 临界值 |
| Test Statistic | 检验统计量 |
| Reject the null | 拒绝原假设 |
| Integrated of order 0 / \(I(0)\) | 零阶单整(即平稳) |
在考试或实际研究中,这被称为确认性分析 (Confirmatory Analysis):
针对你的数据: 你的 ADF 结果(之前讨论的 \(p=0.97\))和这里的 KPSS 结果(拒绝平稳性)完全吻合。两者共同证明了:SP500 原始价格序列绝对是不平稳的。
# lets test SP500's first differences
kpss.test.d <- ur.kpss(diff.xts(SP500$SP500),
type = c("mu")
) # constant deterministic component
summary(kpss.test.d)##
## #######################
## # KPSS Unit Root Test #
## #######################
##
## Test is of type: mu with 10 lags.
##
## Value of test-statistic is: 0.4739
##
## Critical value for a significance level of:
## 10pct 5pct 2.5pct 1pct
## critical values 0.347 0.463 0.574 0.739
# the KPSS test statistic (0.4739) is slightly higher than
# the 5% critical value (0.463), but on the other hand
# lower than 1% critical value
# so we CANNOT reject the null about
# STATIONARITY of SP500's first differences
# on 1% significance level, but we slightly reject
# the null at 5% level
# looking on the graph of diff(SP500)
# one can finally conclude that SP500 ~ I(1)
# conclusion: all tests give (almost) identical result:
# SP500 ~ I(1)这次测试是对 S&P 500 一阶差分(First Difference) 进行的 KPSS 检验。如果说上一次对原始数据的测试是“确诊不平稳”,那么这一次就是为了“证明差分后变老实了”。
以下是详细解读:
diff.xts(SP500$SP500):
关键变量。测试的不再是价格,而是价格的变化量。type = "mu":
依然是测试均值平稳(Level
Stationarity)。即:价格的波动是否围绕着一个固定的常数(平均收益)跳动。通俗解释:这个结果处于“边界线”上。相比原始数据那惊人的 21.82,差分后的 0.47 已经非常接近平稳状态了。在金融实务中,我们通常会结合之前的 PP 检验(那个 -70 的巨数值)来综合判断,认为它在 1% 水平下是平稳的。
这是你这两次操作的终极对比表,也是考试最喜欢考的逻辑链:
| 比较维度 | 原始数据 (Level) | 一阶差分 (First Difference) |
|---|---|---|
| 测试对象 | \(SP500\) (价格) | \(\Delta SP500\) (涨跌幅) |
| KPSS 统计量 | 21.8263 (爆表) | 0.4739 (显著下降) |
| 与临界值比较 | 远大于 1% 临界值 (0.739) | 小于 1% 临界值 (0.739) |
| 原假设 (\(H_0\)) 判定 | 坚决拒绝平稳 | 1% 水平下接受平稳 |
| 结论 (Conclusion) | 不平稳 (Non-stationary) | 平稳 (Stationary) |
Analysis of First Differences (KPSS Test):
在金融数据中,这通常是因为 S&P 500 的波动具有“波动率聚集”(Volatility Clustering)的特征(即今天大波动,明天大概率也大波动)。这种微弱的非平稳性有时会被 KPSS 捕捉到。但在标准的单位根判定中,我们已经可以很有信心地说它已经完成了从 \(I(1)\) 到 \(I(0)\) 的转变。
# lets test SP500's first differences
kpss.test.d <- ur.kpss(diff.xts(SP500$SP500, differences = 2),
type = c("mu")
) # constant deterministic component
summary(kpss.test.d)##
## #######################
## # KPSS Unit Root Test #
## #######################
##
## Test is of type: mu with 10 lags.
##
## Value of test-statistic is: 0.0068
##
## Critical value for a significance level of:
## 10pct 5pct 2.5pct 1pct
## critical values 0.347 0.463 0.574 0.739
# the KPSS test statistic (0.4739) is slightly higher than
# the 5% critical value (0.463), but on the other hand
# lower than 1% critical value
# so we CANNOT reject the null about
# STATIONARITY of SP500's first differences
# on 1% significance level, but we slightly reject
# the null at 5% level
# looking on the graph of diff(SP500)
# one can finally conclude that SP500 ~ I(1)
# conclusion: all tests give (almost) identical result:
# SP500 ~ I(1)这段代码展示了你对 S&P 500 数据进行了二阶差分 (Second-order Differencing) 后的平稳性检验。
以下是对代码、参数及结果的详细解读:
在时间序列分析中,differences = 2
表示对序列执行二阶差分 (Second-order
differencing)。
⚠️ 重要提醒(过度差分 Over-differencing):
通常情况下,金融资产价格(如 S&P
500)的一阶差分(即收益率)已经是平稳的 \(I(0)\)。如果你使用了
differences = 2,你是在对收益率再求一次差分。这虽然会产生一个统计上“非常平稳”的序列(如你的结果
0.0068),但这可能引入了不必要的自相关性
(Autocorrelation)
和噪声,这种做法在计量分析中通常被称为过度差分
(Over-differencing)。除非一阶差分确实不平稳,否则通常不建议使用二阶差分。
| 代码部分 | 术语 (中文/英文) | 含义解释 |
|---|---|---|
diff.xts(...) |
差分 (Differencing) | 针对时间序列对象 (Time series object),计算相邻观测值的差值。 |
differences = 2 |
二阶差分 (Second-order differencing) | 指定对数据进行两次差分操作。 |
type = "mu" |
均值平稳 (Level Stationarity) | 检验序列是否围绕常数均值平稳(不包含时间趋势项)。 |
ur.kpss(...) |
KPSS 检验 (KPSS Test) | 零假设 (\(H_0\)) 为序列是平稳的。 |
summary(...) |
摘要 (Summary) | 输出检验的详细统计结果,包括临界值等。 |
Value of test-statistic is: 0.0068
Critical value for a significance level of:
10pct 5pct 2.5pct 1pct
critical values 0.347 0.463 0.574 0.739
结论: 因为你的统计量 0.0068 远远小于所有显著性水平的临界值(包括最严苛的 0.347),根据 KPSS 的判定规则: > 由于统计量未超过临界值,我们无法拒绝原假设 (\(H_0\))。 > 结论:该序列是平稳的。
事实上,0.0068 这个值极低,说明该序列极度平稳(或者说,通过二阶差分,序列的波动特征已经被极大地平滑,甚至可能已经造成了某种程度的数据扭曲)。
如果你发现你的数据在 differences = 1
时就已经通过了平稳性检验(即统计量小于临界值),那么建议改回
differences = 1。
对于金融时间序列(如股票指数),过度差分虽然能通过平稳性检验,但由于丢失了原始收益率的信息,通常会使后续的模型(如 ARIMA 预测)失去经济学意义。
ur.dfdf.test <- ur.df(SP500$SP500, # vector tested
type = c("drift"), # constant deterministic ; c("none", "drift", "trend");
# component (variant 2 of the test)
lags = 0) # lags for augmentation of ADF part; Number of lags for endogenous variable to be included.
summary(df.test)
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 2.323e-01 8.855e-01 0.262 0.793
## z.lag.1 -1.436e-05 6.170e-04 -0.023 0.981
## Value of test-statistic is: -0.0233 0.4271
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78lags=0: DF test (设置为 0 表示执行的是标准的 DF
检验(Dickey-Fuller),而不是增强型(ADF)。这意味着我们假设残差项里没有自相关)lags=1: ADF test with 1 lagtype:
none: no deterministic component,
无截距项、无趋势项,纯随机游走模型,围绕零均值波动drift: constant deterministic component,
包含一个截距项,允许序列围绕一个非零均值波动trend: constant + time trend deterministic component,
包含一个截距项和一个时间趋势项,允许序列围绕一个随时间变化的趋势线波动ur.df (lags = 1 / 2 / 3)adf.test <- ur.df(SP500$SP500,
type = c("drift"),
lags = 3)
summary(adf.test)
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) ...
## z.lag.1 ...
## z.diff.lag1 ...
## z.diff.lag2 ...
## z.diff.lag3 ...
## Value of test-statistic is: 0.2906 0.6418
##
## Critical values for test statistics:
## 1pct 5pct 10pct
## tau2 -3.43 -2.86 -2.57
## phi1 6.43 4.59 3.78type = "drift": intercept only; use trend
if a deterministic trend should be includedlags = 1, 2, 3...: ADF augmentations; add enough lags
to absorb residual autocorrelationtau2 = 0.1542 for lags = 1 and
tau2 = 0.2906 for lags = 3 both imply fail to
reject \(H_0\).bgtestresids_ <- as.data.frame(adf.test@testreg$residuals)
colnames(resids_) <- "res"
bgtest(res ~ 1, data = resids_, order = 1)
##
## Breusch-Godfrey test for serial correlation of order 1
## data: res ~ 1
## LM test = 17.14, df = 1, p-value = 3.472e-05order = 1, 2, 3...: test serial correlation up to the
chosen lag orderlags = 0 is too short; the residuals are strongly
autocorrelated.lags = 1 improves the fit, but higher-order BG tests
can still reject.lags = 2 is the first clearly acceptable choice here:
BG p-values become comfortably larger than 0.05.testdf2testdf2(variable = SP500$SP500,
test.type = "c",
max.augmentations = 3,
max.order = 5)
## augmentations adf p_adf bgodfrey.statistic bgodfrey.statistic.1 bgodfrey.statistic.2 p_bg.p.value.1 p_bg.p.value.2
## 1 0 -0.0232722 0.9537731 4324 17.140403812 1 25.994309992 0.0000347159 0.0000022668
## 2 1 0.1541788 0.9681014 4323 0.037285076 2 9.080113222 0.8468857921 0.0106728023
## 3 2 0.2741880 0.9764016 4322 0.000353397 3 0.005701143 0.9850015701 0.9971534876
## 4 3 0.2905854 0.9770663 4321 0.000008764 4 0.002948205 0.9976380044 0.9985269836augmentations: candidate ADF lag lengthadf / p_adf: unit-root statistic and
p-valuep_bg.p.value.*: BG residual autocorrelation checksaugmentations = 2, which is
the cleanest usable ADF specification in this example.ur.pppp.test <- ur.pp(SP500$SP500,
type = c("Z-tau"),
model = c("constant"))
pp.test.d <- ur.pp(diff.xts(SP500$SP500),
type = c("Z-tau"),
model = c("constant"))
## Level series
## Value of test-statistic Z-tau: 0.363
## Critical values: 1pct -3.43, 5pct -2.86, 10pct -2.56
##
## First difference
## Value of test-statistic Z-tau: -70.7898
## Critical values: 1pct -3.43, 5pct -2.86, 10pct -2.56type = "Z-tau": t-statistic version;
Z-alpha is the alternative coefficient-based versionmodel = "constant": intercept only; use
trend if a deterministic trend should be allowedZ-tau = 0.363, which is higher than the
5% critical value -2.86, so we cannot reject
non-stationarity.Z-tau = -70.7898, which is far below
all critical values, so we reject non-stationarity.ur.kpsskpss.test <- ur.kpss(SP500$SP500,
type = c("mu"))
kpss.test.d <- ur.kpss(diff.xts(SP500$SP500),
type = c("mu"))
## Level series
## Value of test-statistic is: 21.8263
## Critical values: 10pct 0.347, 5pct 0.463, 2.5pct 0.574, 1pct 0.739
##
## First difference
## Value of test-statistic is: 0.4739
## Critical values: 10pct 0.347, 5pct 0.463, 2.5pct 0.574, 1pct 0.739
##
## Second difference
## Value of test-statistic is: 0.0068type
"mu": level stationarity, H0: 均值平稳tau : for trend stationarity, H0: 趋势平稳21.8263 is far above
0.739, so we reject stationarity.0.4739 is much smaller than
the level result and is close to the 5% boundary; it is clearly below
the 1% critical value.0.0068 is very small, but
this is likely over-differencing rather than a preferred modeling
choice.