A * X_t = β₀ + β₁ * X_{t−1} + u_t -> shock ortogonal u_t (Based on economic theory)
library(dplyr)
library(zoo)
library(vars)
library(ggplot2)
library(gridExtra)
library(tibble)
data <- read.csv("M5_Vector_Autoregression/MFx Module 5, Part II SVAR Workfile/MFx_Module 5_Part II_SVAR_Workfile_Sims.csv")
data$date <- as.yearqtr(as.Date(data$dateid01))
data <- data %>%
mutate(
ly = log(y),
lm = log(m1),
lp = log(cpi),
lxr = log(xr),
lcp = log(cmp)
)
sample_data <- data %>%
filter(date >= as.yearqtr("1958 Q4") & date <= as.yearqtr("1991 Q2"))
Sims argued that the shocks he had initially identified as exogenous
were probably not totally exogenous, and that the Fed was probably
reacting to other variables or leading indicators he had not considered
in his first estimation.
var1_data <- sample_data %>%
dplyr::select(ly, lm, lp, ff) %>%
na.omit()
var1_model <- VAR(var1_data, p = 14, type = "const")
# Compute impulse response functions
irf_var1 <- irf(var1_model, n.ahead = 35, boot = TRUE)
vars <- colnames(var1_data)
# Create IRF grid plots
plot_list <- list()
for (i in seq_along(vars)) {
for (j in seq_along(vars)) {
# Point estimate
response <- irf_var1$irf[[vars[j]]][, i]
# Estimate 1 S.E. from 95% CI, then scale to ±2 S.E.
stderr <- (irf_var1$Upper[[vars[j]]][, i] - irf_var1$Lower[[vars[j]]][, i]) / 4
df <- tibble(
period = 1:length(response),
response = response,
upper = response + 2 * stderr,
lower = response - 2 * stderr
)
p <- ggplot(df, aes(x = period, y = response)) +
geom_line(color = "blue", size = 0.5) +
geom_ribbon(aes(ymin = lower, ymax = upper), fill = "red", alpha = 0.3) +
geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
labs(title = paste("Response of", vars[i], "to", vars[j])) +
theme_minimal(base_size = 9) +
theme(
plot.title = element_text(size = 9),
axis.text = element_text(size = 7),
axis.title = element_blank()
)
plot_list[[length(plot_list) + 1]] <- p
}
}
# Combine in 4x4 grid
grid.arrange(grobs = plot_list, ncol = 4,
top = "Response to Cholesky One S.D. Innovations ±2 S.E. (VAR1: ly, lm, lp, ff)")
The impulse response functions align with Sims’ interpretation
that monetary policy shocks are not fully exogenous. The Federal Funds
rate responds systematically to shocks, suggesting that the Fed adjusts
interest rates in reaction to broader economic conditions—consistent
with Sims’ later view that what appeared to be exogenous policy shifts
may in fact reflect endogenous responses to variables or indicators
omitted from the initial model.
Sims modifed the VAR by
including commodity prices and exchange rate to better isolate purely
exogenous shocks and mitigate the price puzzle.
var2_data <- sample_data %>%
dplyr::select(ly, lm, lp, lxr, lcp, ff) %>%
na.omit()
var2_model <- VAR(var2_data, p = 14, type = "const")
irf_var2 <- irf(var2_model, n.ahead = 35, boot = TRUE)
vars <- colnames(var2_data)
plot_list <- list()
for (i in seq_along(vars)) {
for (j in seq_along(vars)) {
response <- irf_var2$irf[[vars[j]]][, i]
# Estimate 1 S.E. and then ±2 S.E. bounds
stderr <- (irf_var2$Upper[[vars[j]]][, i] - irf_var2$Lower[[vars[j]]][, i]) / 4
df <- tibble(
period = 1:length(response),
response = response,
upper = response + 2 * stderr,
lower = response - 2 * stderr
)
p <- ggplot(df, aes(x = period, y = response)) +
geom_line(color = "blue", size = 0.5) +
geom_ribbon(aes(ymin = lower, ymax = upper), fill = "red", alpha = 0.3) +
geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
labs(title = paste("Response of", vars[i], "to", vars[j])) +
theme_minimal(base_size = 8) +
theme(
plot.title = element_text(size = 8),
axis.text = element_text(size = 6),
axis.title = element_blank()
)
plot_list[[length(plot_list) + 1]] <- p
}
}
grid.arrange(grobs = plot_list, ncol = 6,
top = "Response to Cholesky One S.D. Innovations +/- 2 S.E. (VAR2: ly, lm, lp, lxr, lcp, ff)")
resp1 <- irf_var1$irf$ff[1:35, 3]
stderr1 <- (irf_var1$Upper$ff[1:35, 3] - irf_var1$Lower$ff[1:35, 3]) / 4
resp2 <- irf_var2$irf$ff[1:35, 3]
stderr2 <- (irf_var2$Upper$ff[1:35, 3] - irf_var2$Lower$ff[1:35, 3]) / 4
df1 <- tibble(
period = 1:35,
response = resp1,
upper = resp1 + 2 * stderr1,
lower = resp1 - 2 * stderr1
)
df2 <- tibble(
period = 1:35,
response = resp2,
upper = resp2 + 2 * stderr2,
lower = resp2 - 2 * stderr2
)
p1 <- ggplot(df1, aes(x = period, y = response)) +
geom_line(color = "blue", linewidth = 0.6) +
geom_ribbon(aes(ymin = lower, ymax = upper), fill = "red", alpha = 0.3) +
geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
labs(title = "Response of lp to ff\nVAR1: No CP/XR", y = "IRF", x = "Period") +
theme_minimal(base_size = 10)
p2 <- ggplot(df2, aes(x = period, y = response)) +
geom_line(color = "blue", linewidth = 0.6) +
geom_ribbon(aes(ymin = lower, ymax = upper), fill = "red", alpha = 0.3) +
geom_hline(yintercept = 0, color = "black", linewidth = 0.4) +
labs(title = "Response of lp to ff\nVAR2: With CP/XR", y = "IRF", x = "Period") +
theme_minimal(base_size = 10)
grid.arrange(p1, p2, ncol = 2,
top = "Price Response to Monetary Policy Shock (Cholesky IRF +/- 2 S.E., 35 Periods")