Introduction

Zhongjun Qu

2025-11-25

Introduction

A scalar process is said to have long memory if its spectral density at frequency \(λ\) is proportional to \(λ^{-2d}\) \((d ≠ 0)\) as \(\lambda \rightarrow 0\) . Long memory processes are characterized by slowly decaying autocorrelations and unbounded spectral densities at the origin. A prominent example is the \(ARFIMA(p,d,q)\) model

\[ A(L)(1-L)^d x_t = B(L)\epsilon_t \]

The Problem of Spurious Long Memory

However, apparent long memory can arise from two fundamentally different sources:

  1. Genuine long memory: True fractional integration where shocks have persistent, hyperbolically decaying effects
  2. Spurious long memory: Short-memory processes contaminated by structural features such as:
    • Occasional level shifts or regime changes
    • Smooth deterministic trends

Distinguishing between these cases is crucial

The Test Methodology

This package implements the test proposed by Qu (2011), which exploits the fact that genuine and spurious long memory exhibit different spectral properties across frequency bands.

The test statistic is based on the derivatives of the local Whittle likelihood function and is of the Kolmogorov-Smirnov type. It does not require specifying:

Installation

# From CRAN (once available)
install.packages("SpuriousMemory")

Load the package:

library(SpuriousMemory)

The RV5min Dataset

The package includes realized volatility data for Japanese Yen/US dollar spot exchange rates from Dec 1, 1986 to Jun 30, 1999 (RV5min).

data(RV5min)
n <- length(RV5min)
cat("Sample size:", n, "\n")
#> Sample size: 2960
cat("Mean:", round(mean(RV5min), 4), "\n")
#> Mean: 0.6671
cat("Std. dev:", round(sd(RV5min), 4), "\n")
#> Std. dev: 0.889

Visualize the series:

plot(RV5min, type = "l", 
     main = "Realized Volatility: Japanese Yen/US Dollar",
     xlab = "Time (days)", ylab = "Log RV", 
     col = "steelblue", lwd = 0.8)
grid()

The persistent fluctuations and high autocorrelations suggest possible long memory, but we need to test whether this is genuine or spurious.

Conducting the Test

Basic Usage

The Longmemorytest() function performs the hypothesis test:

H₀: x_t is a stationary long-memory process
H₁: x_t is affected by level shifts or smooth trends (spurious long memory)

result <- Longmemorytest(log(RV5min), demean = TRUE, alpha = 0.05)
#> 
#> --- Spurious Long Memory Test (Qu, 2011) ---
#> n = 2960, m = 269 (n^0.7), alpha = 5.00%
#> d estimate: 0.4739
#> 
#> epsilon = 0.02: W = 0.414 (cv = 1.252) Does Not Reject
#> epsilon = 0.05: W = 0.370 (cv = 1.155) Does Not Reject
#> --------------------------------------------

Understanding the Output

The test provides two test statistics with different trimming parameters \(\epsilon = 0.02, 0.05\)

Interpretation:

Technical Details

The test uses:

For the RV5min data, both tests fail to reject at the 5% level, suggesting the long memory is genuine.

Accessing Results

Extract detailed results programmatically:

# Local Whittle estimates
result$d_estimate
#> [1] 0.4738663

# Test statistics
result$test_stat_eps02  # W statistic (ε = 0.02)
#> [1] 0.4143006
result$test_stat_eps05  # W statistic (ε = 0.05)
#> [1] 0.3696945

# Critical values
result$critical_value_eps02
#> [1] 1.252
result$critical_value_eps05
#> [1] 1.155

# Rejection decisions
result$reject_eps02
#> [1] FALSE
result$reject_eps05
#> [1] FALSE

Simulated Examples

We examine two scenarios to illustrate the test’s behavior under different DGP.

Example 1: Genuine Long Memory (ARFIMA)

Generate an \(ARFIMA(0, 0.4, 0)\) process:

library(fracdiff)
set.seed(123)

# Simulate ARFIMA(0, d, 0) with d = 0.4
x_genuine <- fracdiff.sim(n = 1000, d = 0.4)$series

# Visualize
oldpar <- par(mfrow = c(1, 2))
plot(x_genuine, type = "l", main = "ARFIMA(0, 0.4, 0) Series", 
     ylab = "Value", col = "darkgreen", lwd = 0.8)
grid()

# ACF shows hyperbolic decay
acf(x_genuine, main = "ACF: Genuine Long Memory", 
    col = "darkgreen", lwd = 2)


par(oldpar)

Apply the test:

result_genuine <- Longmemorytest(x_genuine, demean = TRUE, alpha = 0.05, 
                                  print_results = TRUE)
#> 
#> --- Spurious Long Memory Test (Qu, 2011) ---
#> n = 1000, m = 126 (n^0.7), alpha = 5.00%
#> d estimate: 0.3637
#> 
#> epsilon = 0.02: W = 0.637 (cv = 1.252) Does Not Reject
#> epsilon = 0.05: W = 0.637 (cv = 1.155) Does Not Reject
#> --------------------------------------------

Result: Both tests fail to reject \(H₀\), correctly identifying genuine long memory.

Example 2: Level Shift (Spurious)

Generate white noise with an abrupt level shift:

set.seed(456)
n <- 1000
shift_point <- 500

# White noise with level shift
x_spurious <- rnorm(n)
x_spurious[shift_point:n] <- x_spurious[shift_point:n] + 3

# Visualize
oldpar <- par(mfrow = c(1, 2))
plot(x_spurious, type = "l", main = "White Noise + Level Shift",
     ylab = "Value", col = "darkred", lwd = 0.8)
abline(v = shift_point, lty = 2, col = "blue", lwd = 2)
grid()

# ACF shows spurious persistence
acf(x_spurious, main = "ACF: Spurious Long Memory",
    col = "darkred", lwd = 2)


par(oldpar)

Apply the test:

result_spurious <- Longmemorytest(x_spurious, demean = TRUE, alpha = 0.05)
#> 
#> --- Spurious Long Memory Test (Qu, 2011) ---
#> n = 1000, m = 126 (n^0.7), alpha = 5.00%
#> d estimate: 0.5045
#> 
#> epsilon = 0.02: W = 3.152 (cv = 1.252) **REJECT**
#> epsilon = 0.05: W = 2.922 (cv = 1.155) **REJECT**
#> --------------------------------------------

Result: Both tests reject \(H₀\), correctly detecting spurious long memory caused by the level shift.

Significance Levels

The test supports \(α ∈ \{0.01, 0.025, 0.05, 0.10\}\). Critical values are tabulated from simulated asymptotic distributions:

Asymptotic Critical Values
Alpha ε = 0.02 ε = 0.05
10% 1.118 1.022
5% 1.252 1.155
2.5% 1.374 1.277
1% 1.517 1.426

References

Primary Reference:

Qu, Z. (2011). A Test Against Spurious Long Memory. Journal of Business & Economic Statistics, 29(3), 423-438. DOI: 10.1198/jbes.2010.09153

Session Info

sessionInfo()
#> R version 4.4.3 (2025-02-28 ucrt)
#> Platform: x86_64-w64-mingw32/x64
#> Running under: Windows 11 x64 (build 26100)
#> 
#> Matrix products: default
#> 
#> 
#> locale:
#> [1] LC_COLLATE=C                          
#> [2] LC_CTYPE=English_United States.utf8   
#> [3] LC_MONETARY=English_United States.utf8
#> [4] LC_NUMERIC=C                          
#> [5] LC_TIME=English_United States.utf8    
#> 
#> time zone: America/New_York
#> tzcode source: internal
#> 
#> attached base packages:
#> [1] stats     graphics  grDevices utils     datasets  methods   base     
#> 
#> other attached packages:
#> [1] fracdiff_1.5-3       SpuriousMemory_1.0.0
#> 
#> loaded via a namespace (and not attached):
#>  [1] digest_0.6.37     R6_2.6.1          fastmap_1.2.0     xfun_0.53        
#>  [5] cachem_1.1.0      knitr_1.50        htmltools_0.5.8.1 rmarkdown_2.29   
#>  [9] lifecycle_1.0.4   cli_3.6.4         sass_0.4.9        jquerylib_0.1.4  
#> [13] compiler_4.4.3    rstudioapi_0.17.1 tools_4.4.3       evaluate_1.0.3   
#> [17] bslib_0.9.0       yaml_2.3.10       rlang_1.1.5       jsonlite_1.9.1