diff --git a/DESCRIPTION b/DESCRIPTION index 3f400b3..1f18a94 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -49,4 +49,4 @@ Config/testthat/edition: 3 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.1 +RoxygenNote: 7.3.2 diff --git a/NAMESPACE b/NAMESPACE index e711666..2031efb 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -7,6 +7,7 @@ S3method(fitted,bayesianVARs_bvar) S3method(pairs,bayesianVARs_predict) S3method(plot,bayesianVARs_bvar) S3method(plot,bayesianVARs_fitted) +S3method(plot,bayesianVARs_irf) S3method(plot,bayesianVARs_predict) S3method(predict,bayesianVARs_bvar) S3method(print,bayesianVARs_bvar) @@ -18,6 +19,7 @@ S3method(summary,bayesianVARs_draws) S3method(summary,bayesianVARs_predict) S3method(vcov,bayesianVARs_bvar) export(bvar) +export(irf) export(my_gig) export(posterior_heatmap) export(specify_prior_phi) diff --git a/R/RcppExports.R b/R/RcppExports.R index cf9c280..313348a 100644 --- a/R/RcppExports.R +++ b/R/RcppExports.R @@ -23,6 +23,10 @@ my_gig <- function(n, lambda, chi, psi) { .Call(`_bayesianVARs_my_gig`, n, lambda, chi, psi) } +irf_cpp <- function(coefficients, factor_loadings, U_vecs, shock, ahead) { + .Call(`_bayesianVARs_irf_cpp`, coefficients, factor_loadings, U_vecs, shock, ahead) +} + sample_PHI_cholesky <- function(PHI, PHI_prior, Y, X, U, d_sqrt, V_prior) { .Call(`_bayesianVARs_sample_PHI_cholesky`, PHI, PHI_prior, Y, X, U, d_sqrt, V_prior) } diff --git a/R/irf.R b/R/irf.R new file mode 100644 index 0000000..291944f --- /dev/null +++ b/R/irf.R @@ -0,0 +1,50 @@ +#' Impulse response functions +#' +#' Effect of a shock on the factors or variables over time +#' +#' @param x An object of type `bayesianVARs_bvar`. +#' @param shock A vector of shocks. If a factor model was used, then `shock` is +#' applied to the factors, and its dimension must be the number of factors. +#' +#' If the Cholesky model was used, then the dimension of `shock` is expected +#' to be equals the number of equations. Note that the contemporaneous effects +#' of a shock in the Cholesky model depend on the ordering of equations. +#' +#' @return Returns a `bayesianVARs_irf` object +#' +#' @examples +#' train_data <- 100 * usmacro_growth[,c("GDPC1", "PCECC96", "GPDIC1", "AWHMAN", "GDPCTPI", "CES2000000008x", "FEDFUNDS", "GS10", "EXUSUKx", "S&P 500")] +#' prior_sigma <- specify_prior_sigma(data=train_data, type="cholesky") +#' mod <- bvar(train_data, lags=2L, draws=2000, prior_sigma=prior_sigma) +#' ir <- irf(mod, shock=c(0,0,0,0,0,0,1,0,0,0)) +#' plot(ir, n_col=2) +#' +#' @export +irf <- function(x, shock, ahead=8) { + if (x$sigma_type == "factor") { + number_of_factors <- dim(x$facload)[2] + if (length(shock) != number_of_factors) { + stop("the shock vector must have dimension equals to the number of factors") + } + } + else if (x$sigma_type == "cholesky") { + if (length(shock) != ncol(mod$PHI)) { + stop("the shock vector must have dimension equals to the number of variables") + } + } + else { + stop("unknown model") + } + + ret <- irf_cpp( + x$PHI, + x$facload, + x$U, + shock, + ahead + ) + + colnames(ret) <- colnames(x$Y) + class(ret) <- "bayesianVARs_irf" + ret +} diff --git a/R/plots.R b/R/plots.R index 102a445..862ef66 100644 --- a/R/plots.R +++ b/R/plots.R @@ -623,3 +623,78 @@ plot.bayesianVARs_predict <- function(x, dates = NULL, vars = "all", ahead = NUL invisible(x) } + +#' @export +plot.bayesianVARs_irf <- function(x, vars = "all", + quantiles = c(0.05,0.25,0.5,0.75,0.95), + n_col = 1L, + ...){ + + n_ahead <- nrow(x) + + if(length(vars)==1L & any(vars == "all")){ + vars <- 1:ncol(x) + }else if(is.character(vars)){ + if(any(base::isFALSE(vars %in% colnames(x)))){ + stop("Elements of 'vars' must coincide with 'colnames(x)'!") + }else{ + vars <- which(colnames(x) %in% vars) + } + }else if(is.numeric(vars)){ + vars <- as.integer(vars) + if(any(vars > ncol(x))){ + stop("'max(vars)' must be at most 'ncol(x)'!") + } + } + var_names <- colnames(x) + + t <- seq_len(n_ahead) + dates <- t-1 + + quantiles <- sort(quantiles) + nr_quantiles <- length(quantiles) + nr_intervals <- floor(nr_quantiles/2) + even <- nr_quantiles%%2 == 0 + + pred_quants <- apply(x, 1:2, quantile, quantiles) + + oldpar <- par(no.readonly = TRUE) + on.exit(par(oldpar), add = TRUE) + M <- length(vars) + par(mfrow=c(min(5,ceiling(M/n_col)),n_col), mar = c(2,2,2,1), mgp = c(2,.5,0)) + for(j in seq_along(vars)){ + plot(t, rep(0, n_ahead), type = "n", xlab="", ylab = "", + xaxt="n", ylim = range(pred_quants[,,vars[j]])) + + axis(side=1, at = t, labels = dates[t]) + mtext(var_names[j], side = 3) + + if(nr_intervals>0){ + for(r in seq.int(nr_intervals)){ + alpha_upper <- 0.4 + alpha_lower <- 0.2 + alphas <- seq(alpha_lower, alpha_upper, length.out = nr_intervals) + if(nr_intervals==1){ + alphas <- alpha_upper + } + polygon(x = c(t, rev(t)), + y = c(pred_quants[r,,vars[j]], rev(pred_quants[r+1,,vars[j]])), + col = scales::alpha("red", alphas[r]), + border = NA) + if(length(quantiles)>2){ + polygon(x = c(t, rev(t)), + y = c(pred_quants[nrow(pred_quants)+1-r,,vars[j]], + rev(pred_quants[nrow(pred_quants)-r,,vars[j]])), + col = scales::alpha("red", alphas[r]), + border = NA) + } + } + if(!even){ + lines(t, pred_quants[ceiling(length(quantiles)/2),,vars[j]], + col = "red", lwd = 2) + } + } + } + + invisible(x) +} diff --git a/R/utility_functions.R b/R/utility_functions.R index f370a3d..83e03ab 100644 --- a/R/utility_functions.R +++ b/R/utility_functions.R @@ -1733,7 +1733,6 @@ predict.bayesianVARs_bvar <- function(object, ahead = 1L, each = 1L, stable = TR # relevant mod settings sv_indicator <- which(object$heteroscedastic==TRUE) - intercept <- object$intercept # data preparation variables <- colnames(object$Y) @@ -2038,10 +2037,10 @@ predict_old <- function(object, n.ahead, stable = TRUE, LPL = FALSE, Y_obs = NA, #' predictions <- predict(mod, ahead = 1L) #' print(predictions) print.bayesianVARs_predict <- function(x, ...){ - cat(paste("\nGeneric functions for bayesianVARs_predict objects:\n", - " - summary.bayesianVARs_predict(),\n", - " - pairs.bayesianVARs_predict(),\n", - " - plot.bayesianVARs_predict() (alias for pairs.bayesianVARs_predict()).\n")) + cat("\nGeneric functions for bayesianVARs_predict objects:\n", + " - summary.bayesianVARs_predict(),\n", + " - pairs.bayesianVARs_predict(),\n", + " - plot.bayesianVARs_predict() (alias for pairs.bayesianVARs_predict()).\n") invisible(x) } diff --git a/man/irf.Rd b/man/irf.Rd new file mode 100644 index 0000000..dada9fc --- /dev/null +++ b/man/irf.Rd @@ -0,0 +1,33 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/irf.R +\name{irf} +\alias{irf} +\title{Impulse response functions} +\usage{ +irf(x, shock, ahead = 8) +} +\arguments{ +\item{x}{An object of type \code{bayesianVARs_bvar}.} + +\item{shock}{A vector of shocks. If a factor model was used, then \code{shock} is +applied to the factors, and its dimension must be the number of factors. + +\if{html}{\out{