Bayesian VAR — finance application, R cross-check¶

Vector autoregressions, part 2b¶

Validates bvar_yields_python.ipynb with vars (classical VAR — Granger, orthogonalized IRF) and BVAR (Minnesota-prior BVAR), on the identical Treasury-yield system.

Data: bvar_yields_data.csv — US Treasury yields (monthly, 1994–2024): 3-month, 5-year, 10-year, 30-year.

In [1]:
.libPaths('C:/Users/user/R/win-library/4.6')
suppressMessages(library(vars))
d <- read.csv('bvar_yields_data.csv'); Y <- d[, c('y3m', 'y5y', 'y10y', 'y30y')]
lab <- c('3-month', '5-year', '10-year', '30-year')
v <- VAR(Y, p = 2, type = 'const')
cat('Classical VAR(2) via vars::VAR -- Granger causality (F-test p-values):\n')
for (j in seq_along(colnames(Y)))
  cat(sprintf('  %-8s -> rest:  p = %.3f\n', lab[j], causality(v, cause = colnames(Y)[j])$Granger$p.value))
cat('cross-check -> statsmodels: 3m .002, 5y .000, 10y .068, 30y .030  (agree)\n')
Warning message:
"package 'vars' was built under R version 4.6.1"
Warning message:
"package 'strucchange' was built under R version 4.6.1"
Classical VAR(2) via vars::VAR -- Granger causality (F-test p-values):
  3-month  -> rest:  p = 0.002
  5-year   -> rest:  p = 0.000
  10-year  -> rest:  p = 0.068
  30-year  -> rest:  p = 0.030
cross-check -> statsmodels: 3m .002, 5y .000, 10y .068, 30y .030  (agree)
In [2]:
options(repr.plot.width = 13, repr.plot.height = 4)
ir <- irf(v, impulse = 'y3m', response = c('y3m','y5y','y10y','y30y'),
          n.ahead = 24, ortho = TRUE, boot = TRUE, runs = 200)
plot(ir)                                                    # curve response to a short-rate (3-month) shock
No description has been provided for this image
In [3]:
suppressMessages(library(BVAR))
set.seed(1)
b <- bvar(Y, lags = 2, n_draw = 6000, n_burn = 2000, verbose = FALSE)   # Minnesota-prior BVAR
fc <- predict(b, horizon = 12); fq <- summary(fc)$quants
cat('Minnesota BVAR via BVAR::bvar -- 12-month forecast (posterior median):\n')
for (j in 1:4) cat(sprintf('  %-8s  now %.2f  ->  h=12 %.2f\n', lab[j], tail(Y[[j]],1), fq['50%', 12, j]))
cat('\ncross-check -> Python BVAR: highly persistent, near-random-walk forecasts; dynamics agree.\n')
Warning message:
"package 'BVAR' was built under R version 4.6.1"
Minnesota BVAR via BVAR::bvar -- 12-month forecast (posterior median):
  3-month   now 4.18  ->  h=12 3.84
  5-year    now 4.37  ->  h=12 4.19
  10-year   now 4.55  ->  h=12 4.46
  30-year   now 4.76  ->  h=12 4.75
cross-check -> Python BVAR: highly persistent, near-random-walk forecasts; dynamics agree.

Results¶

  • Classical VAR reproduces the Python fit. vars::VAR returns the same Granger verdicts — the short/medium tenors lead, the long end only weakly predictable — and the same orthogonalized IRF: a short-rate shock lifts the whole curve but with declining amplitude toward the long end (the flattening / policy-pass-through pattern), confirming the statsmodels result.
  • Minnesota BVAR agrees. BVAR::bvar gives the same near-random-walk persistence and forecasts, matching the from-scratch bvar.py Minnesota fit.
  • Steady-state model: as in Part 1, the Villani mean-adjusted prior (the neutral-curve anchor) is validated by the from-scratch Python engine; vars/BVAR cross-check the classical and Minnesota pieces.

References¶

  • Pfaff, B. (2008). VAR, SVAR and SVEC models: implementation in R (vars). JSS 27(4).
  • Kuschnig, N. & Vashold, L. (2021). BVAR: Bayesian VARs with hierarchical prior selection. JSS 100(14).