1 引言:Random Walk, Stationarity and Spurious Regression

###########################################################################
#       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
tail(SP500)
##        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
class(SP500)
## [1] "xts" "zoo"
# Plot of SP500 index
plot(SP500$SP500, main = "SP500 index")

# Basing on visual inspection of data we can say that
# the time series is non-stationary
# 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
plot(SP500$SP500, main = "SP500 index")

2 DF 检验 with ur.df, lags = 0

与 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):

  • (\(H_0\)) 始终是一致的:原假设 (\(H_0\))序列存在单位根 (Unit Root),即序列是非平稳的 (Non-stationary)。
  • p > 0.05: data is non-stationary
  • p < 0.05: data is stationary

这段代码执行的是金融时间序列分析中极其重要的一步:单位根检验(Unit Root Test)。它的目的是判断标普 500 指数是否是“平稳”的。

2.1 原始序列的 DF 检验:代码与参数解读

这段代码使用了 urca 包中的 ur.df() 函数。

  • SP500$SP500:测试对象。即标普 500 指数的点位数据。
  • type = "drift":模型类型。
    • 时间序列模型通常有三种:纯随机游走(none)、带漂移项(Drift,即有常数截距)、带趋势项(Trend,即随时间线性增长)。

    • 这里选择 drift 是假设股市虽然波动,但可能存在一个基本的常数增长背景。

      选项 包含成分 对应模型 (Model Type) 常见视觉特征
      “none” 纯随机游走 围绕 0 轴波动
      “drift” 截距 (Intercept) 带漂移随机游走 围绕非零均值波动
      “trend” 截距 + 时间趋势 带趋势随机游走 随时间有明显线性偏斜
  • lags = 0:滞后阶数。
    • 设置为 0 表示执行的是标准的 DF 检验(Dickey-Fuller),而不是增强型(ADF)。这意味着我们==假设残差项里没有自相关==。
  • summary(df.test):打印详细的统计报告,告诉我们检验的具体结果。

2.2 原始序列的 DF 检验:注释翻译

代码中的注释解释了统计学的术语:

  • vector tested:被检测的一串数字。
  • constant deterministic component:确定性常数部分。简单说就是假设数据里包含一个==不随时间改变的“底数”==。
  • variant 2 of the test:这是 DF 检验的第二种变体(带常数项,不带时间趋势)。

2.3 原始序列的 DF 检验:输出结果解读

要看懂这个复杂的表格,你只需要盯住两个关键点:

2.3.1 1. 关键统计量 (Value of test-statistic)

输出显示:Value of test-statistic is: -0.0233 0.4271

  • 第一个数字 -0.0233 对应的是 tau2(即检验平稳性的 t 统计量)。
  • 第二个数字 0.4271 对应的是 phi1(检验常数项是否显著)。

2.3.2 2. 临界值对比 (Critical values)

我们需要将统计量与底部的临界值表进行对比。

  • 判定规则:如果 test-statistic 小于 临界值,则拒绝原假设(即序列是平稳的)。
  • 实际情况:我们的 -0.0233 远远 大于 5% 水平下的 -2.86

2.4 原始序列的 DF 检验:最终结论

标普 500 指数是不平稳的(存在单位根)。

  • 为什么? 因为统计量 -0.0233 没能闯过任何一个临界值的关卡(甚至连 10% 的阈值 -2.57 都没达到)。
  • 这意味着: 股票指数具有“记忆性”,它不是围绕某个均值波动的,而是具有随机游走特征。如果你想对它进行建模分析,通常需要先进行差分(Differencing)处理(即算收益率,而不是看绝对点位)。

小贴士: Pr(>|t|) 里的 0.981 也印证了这一点——由于 p 值非常大,我们无法拒绝“存在单位根(不平稳)”的说法。

3 DF 残差自相关诊断 with bgtest

# 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),主要关注残差项的自相关问题。


3.1 残差自相关诊断:代码逐行解释

代码行 功能解释
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)

3.2 残差自相关诊断:参数详解

针对 bgtest() 函数:

  • res ~ 1: 检验公式。因为我们是直接对残差本身进行检验,所以公式只有截距项(Constant)。
  • data = resids_: 指定包含残差数据的数据框。
  • order = 1: 指定检验的滞后阶数 (Order of Lags)。这里设置为 1,表示检查是否存在 一阶自相关 (AR(1))

3.3 残差自相关诊断:输出结果解读

输出显示 p-value = 3.472e-05

  • 原假设 (\(H_0\)): 残差中不存在序列相关 (No serial correlation)。
  • 观测值: \(p\) 值(约 \(0.0000347\))远远小于 \(0.05\)
  • 结论: 极度显著。拒绝原假设,这意味着残差中存在序列相关。

3.4 残差自相关诊断:计量背景

代码中的注释揭示了计量分析中的一个核心矛盾:

  1. 单位根结论: > tau statistic (-0.0233) is higher than the 5% critical value (-2.86) 由于 \(-0.0233 > -2.86\)(落在非拒绝域),我们无法拒绝原假设,认为 SP500 序列具有单位根 (Unit Root),即非平稳 (Non-stationary)

  2. 问题的关键: > to be sure that conclusions may be drawn... check whether there is no autocorrelation in residuals Dickey-Fuller (DF) 检验的一个前提假设是残差项必须是白噪声 (White Noise)。如果残差中存在自相关(如 BG 检验所示),那么 DF 检验的统计量就不再有效,结论可能产生偏差。

3.5 从 DF 到 ADF:改进建议

由于你的 BG 检验结果显示存在显著的自相关,这意味着你之前使用的 lags = 0 的 DF 检验是不充分的

改进方案: 你应该增加滞后项,改用 增广迪基-福勒检验 (Augmented Dickey-Fuller Test, ADF)

  • ur.df() 中尝试增加 lags 参数(例如使用 lags = 1 或通过信息准则自动选择 selectlags = "AIC")。
  • 目标是找到一个滞后阶数,使得 bgtest\(p\) 值大于 \(0.05\),从而确保残差项不再有序列相关。

4 公式语法补充:常见示例

  • ~ (Tilde/Formula Operator): 可以读作“由…决定”或“关于…的函数”。它将变量分为两部分:
    • 左侧 (Left-hand side, LHS): 因变量 (Dependent Variable / Response),即你想分析的目标。
    • 右侧 (Right-hand side, RHS): 自变量 (Independent Variables / Predictors),即解释变量。
  • 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)

5 二阶序列相关测试 with bgtest, order = 2

bgtest(res ~ 1, data = resids_, 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) 进行的测试。

5.1 一阶差分 ADF:参数解释

  • res ~ 1: 检验目标。表示对残差序列 res 本身进行建模(仅包含截距项/均值)。
  • order = 2: 滞后阶数。这意味着检验不仅考虑上一期 (\(t-1\)) 的影响,还考虑上上期 (\(t-2\)) 的影响。它会检查残差是否受到过去两个时点数值的显著影响。

5.2 一阶差分 ADF:结果解读

  • LM test = 25.994: 这是 Lagrange Multiplier 检验统计量。数值越大,说明观测到的自相关性越强。
  • df = 2: 自由度。对应于我们检验的滞后阶数(order = 2)。
  • p-value = 2.267e-06: 这是核心判定指标(约等于 \(0.000002267\))。

5.2.1 结论 (Conclusion)

由于 \(p < 0.05\),我们拒绝原假设 (\(H_0\): 无序列相关)。

简单一句话总结: 即使考虑了两个滞后阶数,残差中依然存在显著的序列相关 (Serial Correlation)。这意味着之前的单位根检验模型(lags = 0)未能提取出数据中所有的系统性信息,其结论依然是不可靠的。

bgtest(res ~ 1, data = resids_, order = 3)
## 
##  Breusch-Godfrey test for serial correlation of order up to 3
## 
## data:  res ~ 1
## LM test = 26.151, df = 3, p-value = 0.000008868
bgtest(res ~ 1, data = resids_, order = 4)
## 
##  Breusch-Godfrey test for serial correlation of order up to 4
## 
## data:  res ~ 1
## LM test = 27.118, df = 4, p-value = 0.00001882
bgtest(res ~ 1, data = resids_, order = 5)
## 
##  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 = 1order = 5 的 Breusch-Godfrey (BG) 检验结果进行对比,我们可以得出以下系统性的结论:

5.3 不同滞后阶数的 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\),存在自相关

5.4 BG 检验的核心总结

5.4.1 一致性:持续的序列相关 (Serial Correlation)

所有阶数(1 到 5)的 \(p\) 值均远小于 0.05。这表明无论我们向后观察多少期,残差中都存在显著的序列相关性。数据并非“白噪声” (White Noise),仍有规律未被模型捕捉。

5.4.2 统计量趋势 (Statistic Trend)

随着 order(滞后阶数)的增加,LM 统计量 总体呈上升趋势(从 17.14 升至 31.55)。这说明更高阶的滞后项对当前残差仍有解释力,模型遗漏的信息较为复杂。


5.5 BG 检验的计量经济学意义

  • 检验失效 (Test Invalidity): 你最初运行的 ur.df(..., lags = 0) 是基于“残差独立同分布 (i.i.d.)”的假设。BG 检验的结果彻底推翻了这个假设。这意味着你之前得到的 tau 统计量和 \(p\) 值是不可信的 (Biased/Invalid)
  • 模型低阶 (Under-specification): 你的原始模型(仅考虑了当期值)过于简单。残差中的自相关通常意味着数据存在高阶动态特征,或者存在未被处理的季节性/趋势性。

5.6 BG 检验的诊断建议

既然残差“不干净”,为了获得可靠的单位根检验结论,你应该:

  1. 增加滞后项 (Augmentation): 将普通的 DF 检验升级为 ADF (Augmented Dickey-Fuller) 检验。在 ur.df 函数中,通过调整 lags 参数来吸收残差中的自相关。
  2. 自动选择滞后 (Automatic Selection): 建议在 ur.df 中使用 selectlags = "AIC""BIC"。这会让 R 自动尝试不同的滞后阶数,直到残差项接近白噪声为止。
  3. 最终标准: 只有当你增加 lags 之后,再次运行 bgtest 得到的 \(p\)大于 0.05 时,该单位根检验的结论才是稳健可靠的。

6 ADF test, lags = 1 with 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

6.1 ADF(lags = 1):代码与参数详解

在这段代码中,你执行了增广迪基-福勒检验 (Augmented Dickey-Fuller Test, ADF)。相比于之前的 DF 检验,它通过引入滞后差分项来解决残差自相关问题。

  • ur.df(..., type = "drift", lags = 1):
    • type = "drift": 模型包含截距项(常数项),适用于均值不为零但没有明显线性时间趋势的时间序列。
    • lags = 1: 关键参数。在回归方程中加入了一阶滞后差分项 \(\Delta y_{t-1}\)。其目的是吸收残差中的序列相关性,使残差项接近白噪声。

6.2 ADF(lags = 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),残差中确实会遗漏重要的动态信息。

6.3 ADF(lags = 1):检验统计量与判定

在输出的底部,你会看到专门用于单位根判断的统计量:

  • Value of test-statistic is: 0.1542 0.5545:
    • 第一个值 0.1542 对应 tau2,用于检验是否存在单位根。
    • 第二个值 0.5545 对应 phi1,这是一个复合假设检验(同时检验是否存在单位根且漂移项为 0)。
  • 判定过程 (Decision Process):
    1. 查找 tau2 的 5% 临界值:-2.86
    2. 比较:\(0.1542 > -2.86\)
    3. 结论:统计量远大于临界值(没有落在拒绝域的左侧),因此无法拒绝原假设 (Fail to reject \(H_0\))

6.4 ADF(lags = 1):对比总结

如果你将 lags 从 1 改为 2,你会发现回归方程中会多出一项 z.diff.lag2 (\(\Delta y_{t-2}\))。

  • 统计量变化: 随着 lags 的增加,tau2 的值通常会发生微调。如果 z.diff.lag2 依然显著,说明需要更高阶的滞后。
  • 模型质量: 增加 lags 的代价是损失自由度。如果增加 lagstau2 依然远大于临界值,那么“序列非平稳”的结论将变得更加稳健。
  • 结论一致性: 对于标普500 (SP500) 这种价格水平数据,无论 lags 是 1 还是 2,通常都会得到非平稳 (Non-stationary) 的结论,因为价格序列通常具有典型的随机游走特征。

6.5 ADF(lags = 1):注释中的建议

你注释掉的 selectlags = c("AIC") 实际上是更推荐的做法。手动尝试 lags = 1lags = 2 属于探索性分析,而使用 AIC (Akaike Information Criterion) 准则可以自动在“模型简洁性”与“残差白噪声化”之间寻找最佳平衡点。

7 ADF, lags = 2, 3… with ur.df

adf.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

7.1 ADF(lags = 3):代码与参数详解

在这段代码中,你执行了增广迪基-福勒检验 (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}\))。其目的是通过这些滞后项吸收残差中的自相关,确保检验结果的稳健性。

7.2 ADF(lags = 3):回归输出分析

summary 展示了该检验背后的线性回归模型详情:

  • 系数显著性 (Coefficients):
    • 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,且不显著。这意味着==序列具有强烈的随机游走特征==。

7.3 ADF(lags = 3):检验统计量与判定

在输出底部,提供了用于最终决策的统计量和临界值:

  • Value of test-statistic is: 0.2906 0.6418:
    • 第一个值 0.2906 对应 tau2(单位根检验统计量)。
    • 第二个值 0.6418 对应 phi1(联合检验统计量)。
  • 判定逻辑 (Decision Logic):
    • 比较: 我们的 tau2 统计量 0.2906 远大于 5% 显著性水平下的临界值 -2.86
    • 结论: 统计量没有落在拒绝域(左侧),因此无法拒绝原假设 (Fail to reject \(H_0\))

7.4 ADF(lags = 3):总结与经济学含义

  • 非平稳性 (Non-stationarity): 即使通过增加 3 个滞后项处理了自相关问题,结果依然坚定地指向:SP500 价格序列是非平稳的,具有单位根
  • 滞后项的价值: 通过观察 z.diff.lag 的显著性,你可以发现数据存在“记忆性”。前两天的价格变动对今天的变动有显著影响,但到第三天这种影响就消失了。
  • 模型诊断: 由于 z.diff.lag3 不显著,如果你追求模型的简洁性(Parsimony),可以考虑退回到 lags = 2。这正是 selectlags = "AIC" 自动优化的逻辑所在。

7.5 ADF 的综合逻辑对比

我们可以把这个逻辑串成一个完整的诊断流程:

检查项 你的假设结果 翻译成“人话”
滞后项显著性 lag3 不显著 “大前天”的消息已经不影响今天了,没必要再往后看了。
残差检验 (BG) \(p > 0.05\) 仪器里没有“滋滋”的杂音了,测量结果现在很可靠。
单位根统计量 tau2 < -2.86 统计结果显示:这只狗是被绳子拴住的,它虽然乱跑,但总会跑回来。
最终定论 Stationary 平稳序列。你可以基于均值去预测它的未来。

7.6 为什么价格序列上很难看到平稳结果?

在现实的金融市场中,如果你在 SP500 的 价格 (Price) 序列上测出了 tau2 < -2.86,通常只有两种可能:

  1. 数据算错了:或者是样本量太小。
  2. 你发现了一台“印钞机”:因为平稳的价格序列意味着存在“均值回归”,你可以通过低买高卖稳定获利。

通常,我们会对价格取对数后做差分,得到 收益率 (Return)。收益率序列通常是平稳的(Stationary),而原始价格序列几乎永远是非平稳的(Non-stationary)。

7.7 单位根检验的类比解释

  • 平稳序列 (Stationary):像一只被绳子系在木桩上的狗。虽然它会乱跑,但最终总会回到木桩(均值)附近。
  • 非平稳序列 (Non-stationary/单位根):像一个喝醉的人在广场上走路。他下一步在哪里,完全取决于他现在在哪里。他没有固定的中心,会越走越远,这种状态就叫“有单位根”。

结论:你的代码显示 tau 统计量(0.2906)远大于临界值(-2.86)。这意味着 SP500 就是那个醉汉,它的价格没有回归规律,是不可预测的非平稳序列。


7.8 残差自相关:体检仪器的“噪音”

我们在做单位根检验时,就像是用仪器测量醉汉。如果仪器本身“滋滋”响(残差自相关),那测量结果就不准。

  • lags = 0 (DF检验):仪器噪音很大,医生说结论不可靠。
  • bgtest (BG检验):这是专门测噪音的。你测了 1 到 5 阶,发现全都在报错(P值小于0.05),说明噪音一直都在。

7.9 滞后项 (Lags):给仪器加装“消音器”

为了让体检结果可靠,我们必须把这些噪音(之前的价格波动影响)处理掉。这就是你把 lags 从 1 改到 3 的原因。

  • lags = 1:考虑了“昨天”的影响,发现噪音小了一点,但还不够。
  • lags = 3 (ADF检验):同时考虑了“昨天、前天、大前天”的影响。
    • 代码输出显示:昨天的影响(lag1)很大,前天的影响(lag2)也有,但大前天的影响(lag3)几乎没有了(不显著)。
    • 最终判定:加了消音器后,结论依然不变——标普500依然是个“醉汉”

8 BG test for ADF residuals with 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
bgtest(res ~ 1, data = resids_, order = 2)
## 
##  Breusch-Godfrey test for serial correlation of order up to 2
## 
## data:  res ~ 1
## LM test = 0.0029482, df = 2, p-value = 0.9985
bgtest(res ~ 1, data = resids_, order = 3)
## 
##  Breusch-Godfrey test for serial correlation of order up to 3
## 
## data:  res ~ 1
## LM test = 0.0036146, df = 3, p-value = 0.9999
bgtest(res ~ 1, data = resids_, order = 4)
## 
##  Breusch-Godfrey test for serial correlation of order up to 4
## 
## data:  res ~ 1
## LM test = 1.2679, df = 4, p-value = 0.8668
bgtest(res ~ 1, data = resids_, order = 5)
## 
##  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?

8.1 自动选择滞后前:参数的通俗含义

  • order = 1 到 5: 这是你检查的深度
    • order = 1:只看“昨天”的误差会不会影响今天。
    • order = 5:一口气检查“过去五天”的误差组合起来会不会对今天产生系统性的干扰。

8.2 自动选择滞后前:结果的通俗解读

看这一组 \(p\) 值:0.9976, 0.9985, 0.9999, 0.8668, 0.2769

  • 全都大于 0.05:而且前几个 \(p\) 值高得离谱(接近 1)。
  • 这意味着什么?: 在统计学里,这叫“无法拒绝原假设”。用人话说:“没病!很干净!” 你的残差项现在已经完美符合了白噪声 (White Noise) 的要求。

8.3 为什么说现在的模型更稳健?

对比一下你之前的操作,逻辑进化如下:

  1. 最初 (lags = 0):到处都是杂音,结论不可信。
  2. 现在 (lags = 3)
    • 当你检查前三阶(order = 1, 2, 3)时,\(p\) 值几乎就是 1。这说明通过在 ADF 检验里加入 3 个滞后项,你已经把最明显的干扰规律给彻底吸收了。
    • 即使你查到第五阶(order = 5),虽然 \(p\) 值降到了 0.2769,但依然远高于 0.05。这说明更远的时间点也没有明显的干扰。

8.4 自动选择滞后前:最终定论

这一组结果给了你底气。你可以非常有信心对手里的这份 SP500 分析报告签字:

  • 模型质量:五星级。残差里已经没有任何“作弊”的关联信息了。
  • 核心结论:标普500 (SP500) 的价格确实具有单位根 (Unit Root)
  • 实战意义:既然它极其符合“随机游走”,那么你想通过简单的“看图说话”或过去的价格水平来预测明天的价格,在统计学上是行不通的。

9 ADF test with 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): 对于第三行的解读

  1. 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.

  2. 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.

  3. Conclusion: Based on these results, we conclude that the SP500 series is non-stationary.

9.1 testdf2 输出:ADF 检验结果列对比表

列名 中文名称 作用 原假设 (\(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:不合格 ❌ (有噪音)

9.2 ADF 与 BG 检验的考试重点归纳

关注点 重点内容
看表顺序 先看右边 (p_bg),再看左边 (p_adf)。
只有右边及格(>0.05)了,左边的结论才有意义。
\(H_0\) 的区别 这是最容易混淆的:
1. ADF 的 \(H_0\) 是我们想拒绝的(不平稳)。
2. BG 的 \(H_0\) 是我们想接受的(模型合格)。
有效行判定 只要有一列 p_bg 小于 0.05,该行即为“无效模型”,应当舍弃,增加滞后项再看下一行。
科学计数法 看到 e-05e-06 这种,在考试中直接视作 < 0.05

快速记忆口诀:

  • BG 大于 0.05:模型“通过体检”,可以看结论。
  • ADF 小于 0.05:数据“表现平稳”,可以做回归。
  • ADF 大于 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的每一行。

10 Phillips-Perron (PP) test with 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) 检验的结果,这是计量经济学中判断时间序列是否“平稳”的常用工具。

以下是针对代码、参数及输出结果的通俗解读:

10.1 PP 检验:代码与参数解释

  • ur.pp(...): 这是执行 PP 检验的主函数。
  • SP500$SP500: 被检测的数据。这里使用的是标普 500 指数的原始价格序列。
  • type = "Z-tau": 指定统计量的类型。这是一种标准化的计算方法,使其结果在解读上与 ADF 检验的 t 统计量非常相似。
  • model = "constant": 模型设定。这里假设数据中包含一个截距项(常数项)。这意味着我们承认数据可能有一个起始水平,但假设它随时间变化的趋势是==随机的(Stochastic)==,而不是像时钟一样精准运动的(Deterministic)。

10.2 PP test参数含义对比表

参数 (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"。这能更好地控制趋势对单位根检验的干扰。

10.2.1 关于 modelconstant vs trend

这是决定检验有效性的关键,取决于数据的视觉特征

  • constant (截距项)
    • 应用场景:数据在某个均值附近波动,没有明显的长期上升或下降路径(如:利率、平稳的收益率)。
    • 数学逻辑\(Y_t = \mu + \gamma Y_{t-1} + u_t\)。模型假设长期均值为 \(\mu\)
  • trend (截距 + 时间趋势)
    • 应用场景:数据有明显的随时间增长或下降的趋势(如:S&P 500 的原始股价、GDP)。
    • 数学逻辑\(Y_t = \mu + \beta t + \gamma Y_{t-1} + u_t\)。模型不仅考虑均值,还考虑了一个线性趋势项 \(\beta t\)
    • 风险:如果你对有明显趋势的数据使用了 constant 模型,检验的功效 (Power) 会大幅下降,容易出现“虚假非平稳”(即明明序列是趋势平稳的,却因模型漏掉了趋势项而无法拒绝非平稳的原假设)。

在 PP 检验中,你注释里提到的“假设任何趋势都是随机的 (stochastic trends)”,实际上是说该检验对异方差和自相关(Autocorrelation)具有稳健性(Robust)。PP 检验通过==对统计量进行修正==,使得它==不需要==像 ADF 检验那样人为地通过==增加滞后项(lags)==来处理序列相关,这是 PP 检验相比 ADF 的==主要优势==之一。


10.3 PP 检验:输出内容解读

  • Test regression with intercept: 告诉我们后台运行了一个带有截距项的回归方程(即 \(\Delta y_t = \alpha + \beta y_{t-1} + \epsilon_t\))。
  • Coefficients (系数表):
    • y.l1 的估计值约为 0.9999。这非常接近 1,在直觉上暗示了这是一个“随机游走”过程,即昨天的价格几乎决定了今天的价格。
  • Value of test-statistic (0.363): 这是检验的核心成绩
  • Critical values (临界值): 这是及格线。对于这种测试,你需要数值越负越好(越小越好)。
    • 1% 显著水平(学霸级标准):-3.43
    • 5% 显著水平(普通标准):-2.86
    • 10% 显著水平(及格边缘):-2.56

10.4 PP 检验:通俗解读

1. 到底在测什么? 这个测试在问一个问题:标普 500 的价格序列是“安分的”还是“浪荡的”?

  • 平稳(Stationary):数据像系了弹簧,虽然会动,但总会回到一个中心值。
  • 不平稳(Non-stationary):数据像一个醉汉在散步(Random Walk),每一步都基于上一步,且没有回头的倾向。

2. 结果怎么看?

  • 我们的“成绩”是 0.363
  • 我们的“及格线”(5% 显著水平)是 -2.86
  • 对比结论:0.363 远大于 -2.86。在坐标轴上,我们的成绩在及格线的右手边,属于无法拒绝原假设的区域。

3. 结论是什么?

  • 学术结论:无法拒绝存在单位根的原假设,该序列是非平稳的。
  • 人话结论标普 500 的价格是不平稳的。它表现出明显的趋势(随时间飘荡),且具有“完全记忆”,随机冲击对它的影响是永久性的。

4. 接下来该怎么办? 因为数据不平稳,你不能直接把这个价格序列放进普通的回归模型里,否则会产生“伪回归”(看起来很有道理其实全是扯淡的关系)。

  • 解决办法:正如讲义建议的,你需要对数据进行“差分”处理(例如计算收益率 Return),然后再测一遍,通常差分后数据就会变得平稳(即 \(I(1)\) 过程)。

10.5 一阶差分 PP 检验:代码与参数解释

# 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 之外另一种常用的==单位根检验方法==。

pp.test.d <- ur.pp(diff.xts(SP500$SP500), type = c("Z-tau"), model = c("constant"))
  • ur.pp(): 执行 Phillips-Perron (PP) 检验 的函数。相比 ADF 检验==通过增加滞后项==(Augmentations)来处理残差自相关,PP 检验使用==非参数==方法来校正统计量,对异方差性(Heteroskedasticity)==更具稳健性==。
  • diff.xts(SP500$SP500):
    • 一阶差分 (First Difference): 计算 \(y_t - y_{t-1}\)
    • 在金融数据中,价格的一阶差分通常代表每日价格变动
  • type = "Z-tau": 指定统计量类型。Z-tau 对应于 t 统计量版本(最常用);另一种是 Z-rho,对应于回归系数版本。
  • model = "constant":
    • 带常数项的模型 (Model with Intercept/Drift): 假设检验回归方程中包含一个截距项 \(\alpha\)。即检验数据是否围绕一个非零均值平稳。

10.6 一阶差分 PP 检验:输出结果解读

10.6.1 核心数值:

  • Value of test-statistic (统计量值): -70.7898
  • Critical values (临界值):
    • 1% (极显著): -3.43
    • 5% (显著): -2.86
    • 10% (较弱): -2.56

10.6.2 逻辑判断:

  1. 原假设 (\(H_0\)): 序列存在单位根(不平稳)。
  2. 判断标准: 如果统计量比临界值更负(Smaller/More negative),则拒绝原假设。
  3. 结论: \(-70.7898 \ll -3.43\)。统计量远小于 1% 临界值。
    • 英文: We strongly reject the null hypothesis of a unit root at the 1% significance level.
    • 中文: 我们在 1% 的显著性水平上强力拒绝存在单位根的原假设。
    • 结论: 一阶差分序列是平稳的 (Stationary)

10.7 一阶差分 PP 检验:与原始数据的对比

这是理解时间序列单整性(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(平稳)。

10.8 一阶差分 PP 检验:考试回答总结

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 还要“猛”,说明差分后的平稳性极其显著,没有任何争议。

11 KPSS 检验 with 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 SP500

KPSS 检验在时间序列分析中扮演着“==反向验证者==”的角色。在考试中,最关键的是不要把它的原假设和 ADF/PP 搞混。

以下是详细的代码、参数及结果解读:


11.1 KPSS 检验:代码与参数解释

kpss.test <- ur.kpss(SP500$SP500, type = c("mu"))
  • ur.kpss(): 执行 KPSS 检验 的函数。
  • SP500$SP500: 被测试的原始序列(水平值 Level)。
  • type = "mu":
    • 均值平稳 (Level Stationarity):检验序列是否围绕一个常数均值平稳。
    • 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\)
    • mu: 只包含常数项(均值)。==H0: 均值平稳==。
    • tau: 包含常数项 加 时间趋势项。==H0: 趋势平稳==。

11.2 KPSS 检验:核心逻辑反转

这是 KPSS 最容易丢分的地方。请牢记以下对照:

特性 ADF / PP 检验 KPSS 检验
原假设 (\(H_0\)) 非平稳 (有单位根 \(I(1)\)) 平稳 (无单位根 \(I(0)\))
备择假设 (\(H_a\)) 平稳 (\(I(0)\)) 非平稳 (\(I(1)\))
判定逻辑 \(p < 0.05\) 推翻“坏结果”,得到“平稳” 统计量 > 临界值 推翻“好结果”,得到“不平稳”

11.3 KPSS 检验:输出结果分析

11.3.1 数值提取:

  • Value of test-statistic (统计量值): 21.8263
  • Critical values (临界值):
    • 1% 显著性水平: 0.739
    • 5% 显著性水平: 0.463

11.3.2 逻辑判断 (Decision Rule):

  1. 比较: 统计量 \(21.8263\) 远大于 \(1\%\) 的临界值 \(0.739\)
  2. 结论 (Reject/Accept):
    • 英文: Since the test statistic exceeds the critical value, we reject the null hypothesis (\(H_0\)).
    • 中文: 由于统计量远大于临界值,我们拒绝原假设。
  3. 最终推论:
    • 既然拒绝了“平稳”的原假设,说明 SP500 原始序列是不平稳的 (Non-stationary)

11.4 KPSS 检验:考试回答术语对照表

英文 (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)\) 零阶单整(即平稳)

11.5 为什么要同时用 ADF 和 KPSS?

在考试或实际研究中,这被称为确认性分析 (Confirmatory Analysis)

  • 如果 ADF 说“不平稳” (\(p > 0.05\)) 且 KPSS 说“不平稳” (拒绝 \(H_0\))
    • 双重保险:结论非常确定,序列就是不平稳的。
  • 如果两者结论矛盾
    • 说明序列可能存在结构性断点 (Structural Break) 或平稳性非常弱,需要进一步检查。

针对你的数据: 你的 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 检验。如果说上一次对原始数据的测试是“确诊不平稳”,那么这一次就是为了“证明差分后变老实了”。

以下是详细解读:

11.6 一阶差分 KPSS:代码与参数

  • diff.xts(SP500$SP500): 关键变量。测试的不再是价格,而是价格的变化量
  • type = "mu": 依然是测试均值平稳(Level Stationarity)。即:价格的波动是否围绕着一个固定的常数(平均收益)跳动。

11.7 一阶差分 KPSS:输出结果解读

  • 检验统计量 (Test-statistic): 0.4739
  • 关键临界值 (Critical Values):
    • 5% 水平: 0.463
    • 1% 水平: 0.739

11.7.1 逻辑诊断 (The Verdict):

  1. 在 5% 显著性水平下: \(0.4739 > 0.463\)。我们拒绝原假设(拒绝平稳)。
  2. 在 1% 显著性水平下: \(0.4739 < 0.739\)。我们无法拒绝原假设(可以认为平稳)。

通俗解释:这个结果处于“边界线”上。相比原始数据那惊人的 21.82,差分后的 0.47 已经非常接近平稳状态了。在金融实务中,我们通常会结合之前的 PP 检验(那个 -70 的巨数值)来综合判断,认为它在 1% 水平下是平稳的


11.8 水平值 vs 一阶差分:KPSS 对比

这是你这两次操作的终极对比表,也是考试最喜欢考的逻辑链:

比较维度 原始数据 (Level) 一阶差分 (First Difference)
测试对象 \(SP500\) (价格) \(\Delta SP500\) (涨跌幅)
KPSS 统计量 21.8263 (爆表) 0.4739 (显著下降)
与临界值比较 远大于 1% 临界值 (0.739) 小于 1% 临界值 (0.739)
原假设 (\(H_0\)) 判定 坚决拒绝平稳 1% 水平下接受平稳
结论 (Conclusion) 不平稳 (Non-stationary) 平稳 (Stationary)

11.9 一阶差分 KPSS:考试总结叙述

Analysis of First Differences (KPSS Test):

  1. Result: The test statistic for the first-differenced series is 0.4739.
  2. Decision: While it slightly exceeds the 5% critical value (0.463), it remains well below the 1% critical value .739).
  3. Comparison: Compared to the level series (\(statistic = 21.82\)), the difference series shows a massive reduction in the st statistic, moving toward the stationary region.
  4. Final Conclusion: Combining this with the previous ADF/PP results, we confirm that the SP500 index is \(I(1)\). The first difference is stationary at the 1% significance level.

11.10 为什么 0.4739 还没完全降到 0.463 以下?

在金融数据中,这通常是因为 S&P 500 的波动具有“波动率聚集”(Volatility Clustering)的特征(即今天大波动,明天大概率也大波动)。这种微弱的非平稳性有时会被 KPSS 捕捉到。但在标准的单位根判定中,我们已经可以很有信心地说它已经完成了从 \(I(1)\)\(I(0)\) 的转变。

  • \(I(0)\) 代表 Integrated of order 0。含义:原始序列本身就是平稳的。
  • \(I(1)\) 代表 Integrated of order 1。含义:原始序列不平稳,但经过一次差分后变得平稳。
# 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) 后的平稳性检验。

以下是对代码、参数及结果的详细解读:


11.11 二阶差分:什么是 differences = 2?

在时间序列分析中,differences = 2 表示对序列执行二阶差分 (Second-order differencing)

  • 一阶差分 (First difference): 考察的是相邻两期的变动,即 \(\Delta X_t = X_t - X_{t-1}\)(通常即收益率)。
  • 二阶差分 (Second difference): 是对“一阶差分”再次进行差分。公式如下: \[\Delta^2 X_t = \Delta X_t - \Delta X_{t-1} = (X_t - X_{t-1}) - (X_{t-1} - X_{t-2}) = X_t - 2X_{t-1} + X_{t-2}\]

⚠️ 重要提醒(过度差分 Over-differencing): 通常情况下,金融资产价格(如 S&P 500)的一阶差分(即收益率)已经是平稳的 \(I(0)\)。如果你使用了 differences = 2,你是在对收益率再求一次差分。这虽然会产生一个统计上“非常平稳”的序列(如你的结果 0.0068),但这可能引入了不必要的自相关性 (Autocorrelation) 和噪声,这种做法在计量分析中通常被称为过度差分 (Over-differencing)。除非一阶差分确实不平稳,否则通常不建议使用二阶差分。


11.12 二阶差分:代码与参数解析

代码部分 术语 (中文/英文) 含义解释
diff.xts(...) 差分 (Differencing) 针对时间序列对象 (Time series object),计算相邻观测值的差值。
differences = 2 二阶差分 (Second-order differencing) 指定对数据进行两次差分操作。
type = "mu" 均值平稳 (Level Stationarity) 检验序列是否围绕常数均值平稳(不包含时间趋势项)。
ur.kpss(...) KPSS 检验 (KPSS Test) 零假设 (\(H_0\)) 为序列是平稳的。
summary(...) 摘要 (Summary) 输出检验的详细统计结果,包括临界值等。

11.13 二阶差分:输出结果解读

Value of test-statistic is: 0.0068
  • 检验统计量 (Test-statistic):这是 KPSS 检验的计算值(0.0068)。
Critical value for a significance level of:
              10pct  5pct 2.5pct  1pct
critical values 0.347 0.463  0.574 0.739
  • 临界值 (Critical values):这是判断的标准。如果你设定的显著性水平 (Significance level) 是 5%,那么临界值就是 0.463

结论: 因为你的统计量 0.0068 远远小于所有显著性水平的临界值(包括最严苛的 0.347),根据 KPSS 的判定规则: > 由于统计量未超过临界值,我们无法拒绝原假设 (\(H_0\))。 > 结论:该序列是平稳的。

事实上,0.0068 这个值极低,说明该序列极度平稳(或者说,通过二阶差分,序列的波动特征已经被极大地平滑,甚至可能已经造成了某种程度的数据扭曲)。


11.14 二阶差分:总结建议

如果你发现你的数据在 differences = 1 时就已经通过了平稳性检验(即统计量小于临界值),那么建议改回 differences = 1

对于金融时间序列(如股票指数),过度差分虽然能通过平稳性检验,但由于丢失了原始收益率的信息,通常会使后续的模型(如 ARIMA 预测)失去经济学意义。

12 ✅ Cheat-Sheet

12.1 DF test with ur.df

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)
## 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.78
  • \(H_0\): time series is not stationary
  • lags=0: DF test (设置为 0 表示执行的是标准的 DF 检验(Dickey-Fuller),而不是增强型(ADF)。这意味着我们假设残差项里没有自相关)
  • lags=1: ADF test with 1 lag
  • type:
    • none: no deterministic component, 无截距项、无趋势项,纯随机游走模型,围绕零均值波动
    • drift: constant deterministic component, 包含一个截距项,允许序列围绕一个非零均值波动
    • trend: constant + time trend deterministic component, 包含一个截距项和一个时间趋势项,允许序列围绕一个随时间变化的趋势线波动
  • Interpretation:
    • The value of the test statistic (t value for z.lag.1) is -0.0233, which is much higher than the 5% critical value (-2.86).
    • The p-value for the lagged term is 0.981, which is much higher than 0.05.
    • Therefore, we cannot reject the null hypothesis about non-stationarity of SP500.

12.2 ADF test with 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.78
  • \(H_0\): time series is not stationary (unit root)
  • type = "drift": intercept only; use trend if a deterministic trend should be included
  • lags = 1, 2, 3...: ADF augmentations; add enough lags to absorb residual autocorrelation
  • Interpretation:
    • For SP500, the lagged differenced terms matter, but the unit-root statistic stays far above the 5% critical value.
    • tau2 = 0.1542 for lags = 1 and tau2 = 0.2906 for lags = 3 both imply fail to reject \(H_0\).
    • Practical conclusion: the level series is non-stationary; the first difference is the relevant stationary transformation.

12.3 BG test for ADF residuals with bgtest

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 1
## data:  res ~ 1
## LM test = 17.14, df = 1, p-value = 3.472e-05
  • Purpose: check whether the ADF residuals are close to white noise
  • \(H_0\): no serial correlation in residuals
  • order = 1, 2, 3...: test serial correlation up to the chosen lag order
  • Interpretation:
    • lags = 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.
    • Use the smallest augmentation that makes the residual diagnostics pass.

12.4 ADF test with testdf2

testdf2(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.9985269836
  • augmentations: candidate ADF lag length
  • adf / p_adf: unit-root statistic and p-value
  • p_bg.p.value.*: BG residual autocorrelation checks
  • Interpretation:
    • Read the table row by row and stop at the first row where the BG p-values are all above 0.05.
    • For SP500, that happens at augmentations = 2, which is the cleanest usable ADF specification in this example.
    • The ADF p-value remains far above 0.05, so the level series is non-stationary.
    • After first differencing, the series becomes stationary, so SP500 is \(I(1)\).

12.5 Phillips-Perron (PP) test with ur.pp

pp.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.56
  • \(H_0\): time series is not stationary
  • type = "Z-tau": t-statistic version; Z-alpha is the alternative coefficient-based version
  • model = "constant": intercept only; use trend if a deterministic trend should be allowed
  • Interpretation:
    • Level series: Z-tau = 0.363, which is higher than the 5% critical value -2.86, so we cannot reject non-stationarity.
    • First difference: Z-tau = -70.7898, which is far below all critical values, so we reject non-stationarity.
    • Practical conclusion: PP confirms the same \(I(1)\) result as ADF.
    • Critical Value: 越负越好(Smaller/More negative),越有利于拒绝非平稳的原假设。

12.6 KPSS test with ur.kpss

kpss.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.0068
  • \(H_0\): stationary
  • type
    • "mu": level stationarity, H0: 均值平稳
    • tau : for trend stationarity, H0: 趋势平稳
  • Decision rule: reject \(H_0\) if the statistic is above the critical value
  • Interpretation:
    • Level series: statistic 21.8263 is far above 0.739, so we reject stationarity.
    • First difference: statistic 0.4739 is much smaller than the level result and is close to the 5% boundary; it is clearly below the 1% critical value.
    • Second difference: statistic 0.0068 is very small, but this is likely over-differencing rather than a preferred modeling choice.
    • Practical conclusion: the original series is non-stationary, while one difference is enough for the main conclusion that SP500 behaves like an \(I(1)\) process.