Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
addc01d
Sketching solution
gabrielkonecny Sep 22, 2024
96a699d
Draft of core functions
gabrielkonecny Sep 24, 2024
326a787
Update 61_irf_compute.R
gabrielkonecny Sep 24, 2024
d28272e
Interface for user input of dates
gabrielkonecny Sep 25, 2024
9a99cc1
Minor updates
gabrielkonecny Sep 26, 2024
f8c7e88
IV First Stage F-stat / Fixing Code
gabrielkonecny Sep 27, 2024
0345233
roxygenize
gabrielkonecny Sep 28, 2024
145b589
Implemented set_dates and description changes
gabrielkonecny Nov 10, 2024
ae8351a
Draft for check_iv and print method
gabrielkonecny Nov 11, 2024
3040e91
Implementation of check_iv
gabrielkonecny Nov 13, 2024
cebe03f
Improving efficiency and solving errors
gabrielkonecny Nov 14, 2024
30477b8
check_iv update
gabrielkonecny Dec 1, 2024
783363d
New roxygen description
gabrielkonecny Dec 4, 2024
bfdc16d
added missing @noRd, first tiny tests
gabrielkonecny Dec 5, 2024
ba90751
added manual_matching in bv_irf
gabrielkonecny Dec 24, 2024
a1b0635
added tinytests for iv
gabrielkonecny Dec 25, 2024
74700f8
prevent github from tracking my personal testing files
gabrielkonecny Dec 25, 2024
acc5c98
doi as text + force instrument names for manual_matching = FALSE
gabrielkonecny Dec 26, 2024
1a26b0b
cleanup bvar: remove old code
gabrielkonecny Dec 26, 2024
7ca2500
Introducing proxyvar argument instead of relying on user to order pro…
gabrielkonecny Dec 26, 2024
124a1ac
proxyvar argument implementation + tinytests
gabrielkonecny Jan 11, 2025
2cc6d47
Update description
gabrielkonecny Feb 3, 2025
ce696a0
Update data
gabrielkonecny Feb 3, 2025
25a1eb8
Prepare examples for meeting + Cleanup
gabrielkonecny Feb 11, 2025
922416c
Cleanup data
gabrielkonecny Feb 12, 2025
30b236c
Update print for check_iv
gabrielkonecny Feb 27, 2025
341570e
Fix formatting references
gabrielkonecny Feb 27, 2025
6c21b23
RMD example proxy SVAR
gabrielkonecny Feb 27, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -316,3 +316,5 @@ TSWLatexianTemp*
*.glstex

# End of https://www.gitignore.io/api/latex
tests/test_file_iv.R
tests/iv_testfile.R
7 changes: 5 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ Date: 2024-02-13
Authors@R: c(person("Nikolas", "Kuschnig", role = c("aut", "cre"), email = "nikolas.kuschnig@wu.ac.at", comment = c(ORCID = "0000-0002-6642-2543")),
person("Lukas", "Vashold", role = "aut", comment = c(ORCID = "0000-0002-3562-3414")),
person("Nirai", "Tomass", role = "ctb"),
person("Gabriel", "Konecny", role = "ctb"),
person("Michael", "McCracken", role = "dtc"),
person("Serena", "Ng", role = "dtc"))
Author: Nikolas Kuschnig [aut, cre] (<https://orcid.org/0000-0002-6642-2543>),
Lukas Vashold [aut] (<https://orcid.org/0000-0002-3562-3414>),
Nirai Tomass [ctb],
Michael McCracken [dtc], Serena Ng [dtc]
Gabriel Konecny [ctb],
Michael McCracken [dtc], Serena Ng [dtc],
Silvia Miranda-Agrippino [dtc], Giovanni Ricco [dtc], Riccardo Degasperi [dtc]
Maintainer: Nikolas Kuschnig <nikolas.kuschnig@wu.ac.at>
Description: Estimation of hierarchical Bayesian vector autoregressive models
following Kuschnig & Vashold (2021) <doi:10.18637/jss.v100.i14>.
Expand All @@ -28,4 +31,4 @@ Suggests: coda, vars, tinytest
License: GPL-3 | file LICENSE
Encoding: UTF-8
LazyData: true
RoxygenNote: 7.3.1
RoxygenNote: 7.3.2
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ S3method(print,bvar_irf_summary)
S3method(print,bvar_resid)
S3method(print,bvar_summary)
S3method(print,bvar_vcovs)
S3method(print,check_iv)
S3method(residuals,bvar)
S3method(rmse,bvar)
S3method(rmse,default)
Expand Down
4 changes: 4 additions & 0 deletions R/10_bvar.R
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,10 @@ bvar <- function(
variables <- name_deps(variables = colnames(data), M = M)
explanatories <- name_expl(variables = variables, M = M, lags = lags)

# if(!is.null(irf$instrument)){instrument <- irf$instrument
# check_iv_result <- check_iv(Y, instrument)
# print(check_iv_result)}


# Priors -----

Expand Down
121 changes: 121 additions & 0 deletions R/12_aux.R
Original file line number Diff line number Diff line change
Expand Up @@ -267,3 +267,124 @@ quantile_check <- function(conf_bands) {

return(quants)
}

#' Set dates
#'
#' Changes rownames to a character string containing dates. Common format of
#' dates or other index is needed if the length of the \emph{instrument} and
#' reduced form residuals differ. In such case, the identification is based on
#' a common subset of residuals and the instrument.
#'
#' @param data Numeric vector, matrix or a data.frame. Note that observations
#' are expected to be ordered from earliest to latest, and variables in the
#' columns.
#' @param start Starting date of the data in form "YYYY-MM-DD".
#' @param frequency Frequency of the data: "year", "quarter", "month", "week" or "day".
#'
#' @return Returns data with rownames containing sequence of dates as character.
set_dates <- function(data, start, frequency) {

# Check if the input is a data frame, matrix, or numeric vector
if (!is.data.frame(data) && !is.matrix(data) && !(is.vector(data) && is.numeric(data))) {
stop("Error: data must be either a data frame, a matrix, or a numeric vector.")
}

# Determine the number of elements to set row names for
num_elements <- if (is.data.frame(data)) {
nrow(data)
} else if (is.matrix(data)) {
nrow(data)
} else {
length(data)
}

# Set the row names or names based on the sequence of dates
rownames(data) <- seq(as.Date(start), by = frequency, length.out = num_elements)

return(data)
}


#' Check IV
#'
#' Intersects the \emph{residuals} and the \emph{instrument} based on an index
#' (e.g. dates) provided in rownames and names, respectively. Returns an error
#' if the intersection is empty.
#'
#' @param residuals Data frame or numeric matrix. During estimation, draw specific residuals
#' are used and rownames are inherited from data.
#' @param instrument Numeric vector.
#' @param proxyvar character string. Variable for which instrument is provided -
#' Needs to correspond to one of the column names of the data used in
#' \emph{bvar}.
#' @param manual_matching If set to TRUE, user is not expected to specify common
#' index for the data and instrument. Instead the length of instrument needs to
#' match the length of residuals (= length(data inputted in bvar) - lags).
#' @return Returns a list of class \code{check_iv} with information on
#' values and indices corresponding to the intersection. Additionally the list
#' contains inputs provided to the function.
#' @noRd
check_iv <- function(residuals, instrument, manual_matching = FALSE,
proxyvar) {

residuals <- data.frame(residuals)

if(manual_matching == TRUE){
dates_residuals <- NULL
dates_instrument <- NULL
common_dates <- NULL

if(!nrow(residuals) == length(instrument)){
stop("manual_matching is TRUE but the length of residuals does not match the length of instrument!
Note that residuals are shorter than the data inputted to bvar, since first l observations of data are not part of residuals,
where l corresponds to number of lags used.")
}

residuals_shortened <- residuals
instrument_shortened <- instrument
} else{

if (!proxyvar %in% colnames(residuals)) {
stop(paste("The proxied variable", proxyvar, "was not found in the column names of residuals."))
}
# Get the dates or other indices
dates_residuals <- rownames(residuals)
dates_instrument <- names(instrument)

# Find the intersection of dates (common dates)
common_dates <- intersect(dates_residuals, dates_instrument)

# If there are no matches and throw an error
if (length(common_dates) == 0) {
stop("Could not match instrument with the data; please provide common indices for both. See `bv_irf` for details.")
}

# Shorten both objects to the common dates
residuals_shortened <- residuals[common_dates,]
instrument_shortened <- instrument[common_dates]
}

out <- structure(mget(c("residuals", "instrument",
"dates_residuals", "dates_instrument",
"residuals_shortened", "instrument_shortened",
"common_dates", "manual_matching")),
class = "check_iv")

return(out)
}


get_swapped_index <- function(residuals, proxyvar) {
# Find the column index of the proxy variable
j <- which(colnames(residuals) == proxyvar)

# Create a sequence of column indices
index <- seq_len(ncol(residuals))

# Swap the first column index with the proxyvar column index
index[1] <- index[j]
index[j] <- 1

return(index)
}

113 changes: 98 additions & 15 deletions R/60_irf_setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,25 @@
#' as well as if and what kind of identification should be used. See the Details
#' section for further information on identification. Identification can be
#' achieved via Cholesky decomposition, sign restrictions (Rubio-Ramirez,
#' Waggoner and Zha, 2010), and zero and sign restrictions (Arias,
#' Rubio-Ramirez and Waggoner, 2018).
#' Waggoner and Zha, 2010), combination of zero and sign restrictions (Arias,
#' Rubio-Ramirez and Waggoner, 2018) or using an external instrument
#' (Stock and Watson 2012, Mertens and Ravn 2013)
#'
#' Identification can be performed via Cholesky decomposition, sign
#' restrictions, or zero and sign restrictions. The algorithm
#' for generating suitable sign restrictions follows Rubio-Ramirez, Waggoner
#' and Zha (2010), while the one for zero and sign restrictions follows
#' Arias, Rubio-Ramirez and Waggoner (2018).
#' restrictions, zero and sign restrictions or using an external instrument.
#' The algorithm for generating suitable sign restrictions follows
#' Rubio-Ramirez, Waggoner and Zha (2010), while the one for zero and sign
#' restrictions follows Arias, Rubio-Ramirez and Waggoner (2018).
#' Note the possiblity of finding no suitable zero/sign restrictions.
#' The proxy SVAR identification follows the implementation in
#' Miranda-Agrippino and Ricco (2021) and examples make use of their instrument
#' extended in Degasperi and Ricco (2021). The implemented proxy SVAR allows
#' for identification using subsample of residuals. This can be useful if the
#' instrument is not available for the full sample period. Therefore only
#' a part of the residuals corresponding to the length of instrument is used.
#' For correct selection of residuals user is expected to specify rownames(data)
#' and names(instrument) in same format. The subset is then based on string
#' matching.
#'
#' @param horizon Integer scalar. The horizon for which impulse responses
#' (and FEVDs) should be computed. Note that the first period corresponds to
Expand All @@ -26,7 +36,7 @@
#' @param identification Logical scalar. Whether or not the shocks used for
#' calculating impulses should be identified. Defaults to \code{TRUE}, i.e.
#' identification via Cholesky decomposition of the VCOV-matrix unless
#' \emph{sign_restr} is provided.
#' \emph{sign_restr} or \emph{instrument} is provided.
#' @param sign_restr Elements inform about expected impacts
#' of certain shocks. Can be either \eqn{1}, \eqn{-1} or \eqn{0} depending
#' on whether a positive, a negative or no contemporaneous effect of a
Expand All @@ -37,20 +47,45 @@
#' \eqn{M - j} zero restrictions can be imposed on the \eqn{j}'th column.
#' @param sign_lim Integer scalar. Maximum number of tries to find suitable
#' matrices to for fitting sign or zero and sign restrictions.
#' @param instrument Numeric vector. If provided, the identification is performed
#' using proxy SVAR. The implemented proxy SVAR allows for different length of
#' instrument and residuals. In such case a common subset is used for the
#' identification. To subset correct observations names(instrument) and
#' rownames(data) are used - they need to have same format. See details
#' @param proxyvar character string. Variable for which instrument is provided.
#' Needs to correspond to one of the column names of the data used in
#' \emph{bvar}.
#' @param manual_matching If set to TRUE, no indices for the data and instrument
#' are needed. Instead, the length of the instrument needs to
#' match the length of the residuals. This rules out the possibility of performing
#' identification on a proper subset of residuals.
#'
#' @return Returns a named list of class \code{bv_irf} with options for
#' \code{\link{bvar}}, \code{\link{irf.bvar}} or \code{\link{fevd.bvar}}.
#'
#' @references
#' Rubio-Ramirez, J. F. and Waggoner, D. F. and Zha, T. (2010) Structural
#' Vector Autoregressions: Theory of Identification and Algorithms for
#' Inference. \emph{The Review of Economic Studies}, \bold{77}, 665-696,
#' \doi{10.1111/j.1467-937X.2009.00578.x}.
#' Arias, J.E. and Rubio-Ramirez, J. F. and Waggoner, D. F. (2018)
#' Arias, J.E. and Rubio-Ramirez, J. F. and Waggoner, D. F. (2018)
#' Inference Based on Structural Vector Autoregressions Identifiied with
#' Sign and Zero Restrictions: Theory and Applications.
#' \emph{Econometrica}, \bold{86}, 2, 685-720,
#' \doi{10.3982/ECTA14468}.
#' doi:10.3982/ECTA14468. \cr
#' Degasperi, R. and Ricco, G. (2021)
#' Information and policy shocks in monetary surprises. Working paper, University of Warwick. \cr
#' Mertens, K., and Ravn, M. O. (2013) The dynamic effects of personal and
#' corporate income tax changes in the United States. \emph{American
#' economic review}, \bold{103(4)}, 1212-1247, doi:10.1257/aer.103.4.1212. \cr
#' Miranda-Agrippino, S., & Ricco, G. (2021) The transmission of monetary
#' policy shocks. \emph{American Economic Journal: Macroeconomics},
#' \bold{13(3)}, 74-107, doi:10.1257/mac.20180124 \cr
#' Rubio-Ramirez, J. F. and Waggoner, D. F. and Zha, T. (2010) Structural
#' Vector Autoregressions: Theory of Identification and Algorithms for
#' Inference. \emph{The Review of Economic Studies}, \bold{77}, 665-696,
#' doi:10.1111/j.1467-937X.2009.00578.x. \cr
#' Stock, J. H., and Watson, M. W. (2012) Disentangling the Channels of the
#' 2007-2009 Recession (No. w18094) \emph{National Bureau of Economic
#' Research}, doi:10.3386/w18094.


#'
#' @seealso \code{\link{irf.bvar}}; \code{\link{plot.bvar_irf}}
#'
Expand All @@ -71,14 +106,32 @@
#' zero_signs <- matrix(c(1, 0, NA, -1, 1, 0, -1, 1, 1), nrow = 3)
#' bv_irf(sign_restr = zero_signs)
#'
#' # Set up structural impulse responses using external instrument with length
#' corresponding to reduced form residuals
#' bv_irf(instrument = istrument)
#'
#' # Prepare to estimate unidentified impulse responses
#' bv_irf(identification = FALSE)
#'
#' # Prepare to estimate SVAR-IV using an indexed instrument for monetary policy
#' # shocks. names(instrument) need to be same format as rownames(data), since
#' # subsetting is based on string matching.
#' data("mpi")
#' bv_irf(instrument = instrument, manual_matching = FALSE, proxyvar = "FEDFUNDS")
#'



bv_irf <- function(
horizon = 12,
fevd = FALSE,
identification = TRUE,
sign_restr = NULL,
sign_lim = 1000) {
sign_lim = 1000,
instrument = NULL,
proxyvar = NULL,
manual_matching = FALSE
) {

# Input checks
horizon <- int_check(horizon, min = 1, max = 1e6,
Expand Down Expand Up @@ -115,13 +168,43 @@ bv_irf <- function(
}
}
# Cholesky

}

# IV

if(!is.null(instrument)){
if (is.numeric(instrument)) {
} else {
stop("Input must be a numeric vector. Multiple instruments are not
supported.")
}
}

if(!manual_matching && !is.null(instrument) &&
is.null(names(instrument))){
stop("No index detected for the object instrument. If manual_matching is
FALSE, names(instrument) need to be specified. For identification to work
correctly a common index for the data and the instrument must be specified.
Alternatively, switch manual_matching to TRUE.")
}

if (!is.null(instrument) && is.null(proxyvar)) {
stop("If 'instrument' is specified, 'proxyvar' must also be specified.")
}

if(!is.null(proxyvar) && !is.character(proxyvar)){
stop("Proxyvar needs to be an object of type character.")
}

# Outputs
out <- list("horizon" = horizon, "fevd" = fevd,
"identification" = identification,
"sign_restr" = sign_restr, "zero" = zero,
"sign_lim" = sign_lim
"sign_lim" = sign_lim,
"instrument" = instrument,
"manual_matching" = manual_matching,
"proxyvar" = proxyvar
)

class(out) <- "bv_irf"
Expand Down
Loading