Hodrick (1992) Standard Errors (Reverse Regression)¶
In the previous post, I calculate Hodrick (1992) standard error IB in a forward regression setting. This post shows how to use the reverse regression approach of Hodrick (1992) to compute standard errors which account for the overlapping nature of predictors.
Prerequisite¶
1 Hodrick (1992) standard errors¶
1.1 Reverse regression approach¶
The reverse regression of the one-period-ahead return on the previous \(h\)-period sum of the predictor is given by:
hodrick1992vcov.reverse <- function(x.var , r.var.ahead, h){
x.mat <- as.matrix(x.var)
r.mat <- as.matrix(r.var.ahead)
# 1. Construct demeaned returns or one-period residuals
ee.mat <- r.mat - colMeans(r.mat)
# ee.mat <- as.matrix(lm(r.var~1)$residuals) # equivalent to the demeaned returns
# 2. Construct sum of squares of predictors
x.mat <- cbind(1, x.mat) # add the constant
T <- nrow(x.mat)
K <- ncol(x.mat)
Exx <- t(x.mat) %*% x.mat / T # compute average of square (1/T) * (X'X)
# Construct the reverse regressor by summing previous h-period values
rev.x.mat = as.matrix(frollsum(x.var, n = h, align = "right"))
# Construct the matrix for sum of squares and standard errors
rev.x.mat <- cbind(matrix(h,T - h +1 ,1) , rev.x.mat[h:T,]) # add the constant and get rid of NAs
rev.ee.mat <- as.matrix(ee.mat[h:T,])
b_reverse <- solve(t(rev.x.mat) %*% rev.x.mat) %*% t(rev.x.mat) %*% r.mat[h:T,]
# Compute the matrix of sum of squares and directly the standard errors
wk <- rev.ee.mat[,1] * rev.x.mat
S <- 1/nrow(wk) * t(wk) %*% wk
vcov_hodrick <- (1 / nrow(wk)) * solve(Exx) %*% S %*% solve(Exx)
std_hodrick <- sqrt(diag(vcov_hodrick))
return(list(b = b_reverse, vcov_hodrick = vcov_hodrick, std_hodrick = std_hodrick, Nobs = nrow(wk)))
}
1.2 Forward regression approach¶
As mentioned in the previous post, the standard long-horizon predictive regression is given by:
\[
r_{t \rightarrow t+h}=\alpha+\beta \cdot x_t+\varepsilon_{t \rightarrow t+h}.
\]
hodrick1992vcov.forward <- function(x.var , r.var.ahead, h){
x.mat <- as.matrix(x.var)
r.mat <- as.matrix(r.var.ahead)
# 1. Construct demeaned returns or one-period residuals
ee.mat <- r.mat - colMeans(r.mat)
# ee.mat <- as.matrix(lm(r.var.ahead~1)$residuals) # equivalent to the demeaned returns
x.mat <- cbind(1, x.mat) # add the constant
T <- nrow(x.mat)
K <- ncol(x.mat)
Exx <- t(x.mat) %*% x.mat / T # compute average of square (1/T) * (X'X)
b <- solve(t(x.mat) %*% x.mat) %*% t(x.mat) %*% r.mat
compute_wk_t <- function(t, h){
wk_t <- matrix(0, nrow = K, ncol = 1)
XX <- matrix(0, nrow = K, ncol = 1)
for (i in 0:(h-1)){
XX <- XX + x.mat[t-i,]
}
wk_t <- ee.mat[t] * XX
return(wk_t)
}
compute_S <- function(h){
S <- matrix(0, nrow = K, ncol = K)
for (t in h:T){
S <- S + (compute_wk_t(t,h) %*% t(compute_wk_t(t,h)))
}
S <- S / T
return(S)
}
S <- compute_S(h)
vcov_hodrick <- (1 / T) * solve(Exx) %*% S %*% solve(Exx)
std_hodrick <- sqrt(diag(vcov_hodrick))
return(list(b = b, vcov_hodrick = vcov_hodrick, std_hodrick = std_hodrick, Nobs = T))
}
1.3 Combine these two methods¶
hodrick1992vcov <- function(x.var , r.var.ahead, h, method = c("forward", "reverse")){
if (method == "forward"){
return(hodrick1992vcov.forward(x.var, r.var.ahead, h))
}
if (method == "reverse"){
return(hodrick1992vcov.reverse(x.var, r.var.ahead, h))
}
}
2 Examples¶
t | x_t | r_t | r_t_plus_1 | r_t_plus_3 | r_t_plus_6 | r_t_plus_12 |
---|---|---|---|---|---|---|
1 | 1.3709584 | 0.0800000 | -0.0344801 | 0.0543657 | 0.1392246 | 0.1188966 |
2 | -0.5646982 | -0.0344801 | 0.0088458 | -0.0062542 | 0.1045764 | 0.0885166 |
3 | 0.3631284 | 0.0088458 | 0.0193802 | 0.0495512 | 0.0290402 | 0.1400495 |
4 | 0.6328626 | 0.0193802 | 0.0213252 | 0.0848590 | 0.1118831 | 0.1849328 |
5 | 0.4042683 | 0.0213252 | 0.0441536 | 0.1108306 | 0.1128342 | 0.1644087 |
6 | -0.1061245 | 0.0441536 | 0.0453517 | -0.0205110 | 0.0688945 | 0.1369073 |
h <- 6
m_ols <- lm(simulate_dt$r_t_plus_6~simulate_dt$x_t)
m_forward <- hodrick1992vcov(x.var = simulate_dt$x_t, r.var.ahead = simulate_dt$r_t_plus_1, h = h, method = "forward")
m_reverse <- hodrick1992vcov(x.var = simulate_dt$x_t, r.var.ahead = simulate_dt$r_t_plus_1, h = h, method = "reverse")
kable(data.table(
b_ols = coef(m_ols)[[2]],
se_ols = sqrt(diag(vcov(m_ols)))[[2]],
se_forward = m_forward$std_hodrick[2],
b_reverse = m_reverse$b[2,],
se_reverse = m_reverse$std_hodrick[2]
))
b_ols | se_ols | se_forward | b_reverse | se_reverse |
---|---|---|---|---|
0.0027597 | 0.0031609 | 0.0033485 | 0.0007351 | 0.0033626 |