# Paper Replications

#### Rubens Moura

#### 2024-04-29

This vignette leverages the MultiATSM package to reproduce some empirical findings from three academic papers centered around the unspanned macroeconomic risk framework. The first segment focuses on replicating the outcomes of Joslin, Priebsch, and Singleton (2014), which laid the foundation for the unspanned risk ATSM literature through a single-country analysis of the U.S. economy. Subsequently, I present the multi-country model extension proposed by Candelon and Moura (Forthcoming), employing a GVAR approach to capture risk factor dynamics. Lastly, I introduce the program designed to replicate results detailed in Candelon and Moura (2023), an extension of the previous framework to investigate the term structure behavior of major emerging markets during the unprecedented COVID\(-19\) pandemic. It is worth highlighting that, due to limited public availability of bond yield data, I employ, in certain instances, simulated data closely matching the original papers’ construction method. Consequently, while the outputs generated by the scripts below may not exactly mirror those from the original papers, the main features of these results are preserved.

A thorough explanation on the usage of the additional functionalities of the MultiATSM package is available at the package vignette.

    library(MultiATSM)

# 1 Joslin, Priebisch and Singleton (2014)

The database used in this replication was constructed by Bauer and Rudebusch (2017) (BR, 2017) and is available at Bauer’s website. In that paper, BR (2017) investigate whether macro-finance term structure models better suit the unspanned macro risk framework by JPS (2014) or the earlier traditional spanned settings as the one by Ang and Piazzesi (2003). Accordingly, BR (2017) intend to replicate some of the empirical results reported in JPS (2014). The R-code used by BR (2017) is also available at Bauer’s website.

Supported by BR (2017)’s data-set, the code below uses the MultiATSM package to estimate the key model parameters from the ATSM along the lines of JPS (2014). The model estimation is performed using the JPS modeling setup.

    #########################################################################################################
    #################################### USER INPUTS ########################################################
    #########################################################################################################
    # A) Load database data
    data("BR_jps_gro_R3")

    # B) Decide on general model inputs
    ModelType <- "JPS"

    StationarityUnderQ <- 0
    BiasCorrection <- 0
    WishForwardPremia <- 1

    Economies <- c("U.S.") # Names of the economies from the economic system
    GlobalVar <- c()
    DomVar <- c("GRO", "INF") # Country-specific variables

    N <- 3 # Number of spanned factors per country

    DataFrequency <- "Monthly" # Frequency of the data
    UnitMatYields <- "Month" # time-unit in which yields are expressed. Available options are "Month" or "Year"

    mat <- c(0.25, 0.5, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) # maturities expressed in years

    #########################################################################################################
    ############################### NO NEED TO MAKE CHANGES FROM HERE #######################################
    #########################################################################################################
    # 2) Minor preliminary work
    C <- length(Economies)
    M <- length(DomVar)
    FactorLabels <- LabFac(N, DomVar, GlobalVar, Economies, ModelType) # Generate the set of labels
    Yields <- t(BR_jps_out$Y)
    W <- BR_jps_out$W[1:N,] # Use the Wpca matrix from BR (2017)
    SpaFac <- W%*%Yields
    rownames(SpaFac) <- FactorLabels$Tables$U.S.[-(1:M)]
    ZZ <- rbind(t(BR_jps_out$M.o), SpaFac) # Complete set of risk factors

    # 3) Prepare the inputs of the likelihood function
    i <- length(Economies)
      # 3.1) Compute the inputs that go directly into the log-likelihood function
      ATSMInputs <- InputsForMLEdensity(ModelType, Yields, ZZ, FactorLabels, mat, Economies, DataFrequency)
      # 3.2) Initial guesses for Variables that will be concentrared out of from the log-likelihood function
      K1XQ <- ATSMInputs$K1XQ
      SSZ <- ATSMInputs$SSZ
      # 3.3) Adjust the inputs which are funtion of the W matrix
      ATSMInputs$Wpca <- W
      ATSMInputs$We <- t(pracma::null(W))
      ATSMInputs$WpcaFull <- rbind(ATSMInputs$Wpca, ATSMInputs$We)
      ATSMInputs$PP <- SpaFac

      # 4) Build the objective function
      f <- Functionf(ATSMInputs, Economies, mat, DataFrequency, FactorLabels, ModelType)

      # 5) Set the optimization settings
      VarLab <- ParaLabels(ModelType, StationarityUnderQ)

      varargin <- list()
      varargin$K1XQ <-list(K1XQ, VarLab[[ModelType]][["K1XQ"]] , NULL , NULL)
      varargin$SSZ <- list(SSZ, VarLab[[ModelType]][["SSZ"]], NULL, NULL)
      varargin$r0 <- list(NULL, VarLab[[ModelType]][["r0"]], NULL, NULL)
      varargin$se <- list(NULL, VarLab[[ModelType]][["se"]], 1e-6, NULL)
      varargin$K0Z <- list(NULL, VarLab[[ModelType]][["K0Z"]], NULL, NULL)
      varargin$K1Z <- list(NULL, VarLab[[ModelType]][["K1Z"]], NULL, NULL)
      varargin$OptRun <-  c("iter off")

      LabelVar<- c('Value', 'Label', 'LB', 'UB') # Elements of each parameter
      for (d in 1:(length(varargin)-1)){ names(varargin[[d]]) <-  LabelVar}

      tol <- 1e-4

      # 6) Optimization of the model
      ModelPara <- Optimization(f, tol, varargin, FactorLabels, Economies, ModelType)$Summary

The tables below compare the ATSM parameter estimates generated from BR (2017) and the MultiATSM. Overall, one can note that the differences in the estimates are economically modest.

Table 1.1: \(Q\)-dynamics parameters
| MultiATSM | BR (2017)
--- | --- | ---
\(r0\) | 0.00055 | -0.00016
\(\lambda_1\) | 0.99670 | 0.99682
\(\lambda_2\) | 0.91488 | 0.95945
\(\lambda_3\) | 0.91488 | 0.87174
Note:
\(\lambda\)’s are the eigenvalues from the risk-neutral feedback matrix and \(r0\) is the long-run mean of the short rate under Q.

Table 1.2: \(P\)-dynamics parameters
| K0Z | K1Z
--- | --- | ---
|  | PC1 | PC2 | PC3 | GRO | INF
BR (2017)
PC1 | 0.07811 | 0.93691 | -0.01307 | -0.02181 | 0.10457 | 0.10033
PC2 | 0.02100 | 0.00582 | 0.97814 | 0.17031 | -0.16719 | -0.04016
PC3 | 0.10047 | -0.01037 | -0.00625 | 0.78346 | -0.03987 | 0.04369
GRO | 0.06904 | -0.00483 | 0.01801 | -0.11117 | 0.88177 | -0.00247
INF | 0.04996 | 0.00185 | 0.00642 | -0.05920 | 0.02767 | 0.98593
MultiATSM
PC1 | 0.07811 | 0.93691 | -0.01307 | -0.02181 | 0.10457 | 0.10033
PC2 | 0.02100 | 0.00582 | 0.97814 | 0.17031 | -0.16719 | -0.04016
PC3 | 0.10047 | -0.01037 | -0.00625 | 0.78346 | -0.03987 | 0.04369
GRO | 0.06904 | -0.00483 | 0.01801 | -0.11117 | 0.88177 | -0.00247
INF | 0.04996 | 0.00185 | 0.00642 | -0.05920 | 0.02767 | 0.98593
Note:
\(K0Z\) is the intercept and \(K1Z\) is feedback matrix from the \(P\)-dynamics.

Table 1.3: Portfolio of yields with errors
| MultiATSM | BR (2017)
--- | --- | ---
se | 0.0000546 | 0.000055
Note:
\(se\) is the standard deviation of the portfolio of yields observed with errors.

It is relevant to highlight that the script above makes use of the principal component weights provided by BR (2017). Such a matrix is simply a scaled-up version of the one provided by the function pca_weights_one_country of this package. Accordingly, despite the numerical differences on the weight matrices, both methods generate time series of spanned factors which are perfectly correlated. Another difference between the two approaches relates to the construction form of the log-likelihood function (llk): while in the BR (2017) code the llk is expressed in terms of a portfolio of yields, the MultiATSM package generates this same input directly as a function of observed yields (i.e. both procedures lead to equivalent llk up to the Jacobian term).

# 2 Candelon and Moura (2021)

The multi-country framework introduced in Candelon and Moura (Forthcoming) was meticulously designed to enhance the tractability of large-scale ATSMs, providing a deeper understanding of the intricate global economic mechanisms that underlie yield curve fluctuations. This framework also reinforces the statistical validity of inference and enhances the predictive capabilities of these models. This novel setup, embodied by the GVAR jointQ model class, is benchmarked against the findings of Jotikasthira, Le, and Lundblad (2015), which are captured by the JLL original model class. The paper showcases an empirical illustration involving China, Brazil, Mexico, and Uruguay.

    #########################################################################################################
    #################################### USER INPUTS ########################################################
    #########################################################################################################
    # A) Load database data
    data("CM_Factors")
    data('CM_Factors_GVAR')
    data('CM_Trade')
    data('CM_Yields')

    # B) Decide on general model inputs
    ModelType <- "GVAR jointQ"  # Options: "GVAR jointQ", "JLL original"

    StationarityUnderQ <- 0
    BiasCorrection <- 1
    WishForwardPremia <- 0
    FPmatLim <- c(24,36)

    Economies <- c("China","Brazil","Mexico", "Uruguay")
    GlobalVar <- c("GBC", "CPI_OECD")
    DomVar <- c("Eco_Act", "Inflation")

    N <- 3 # Number of spanned factors per country

    OutputLabel <- "CM_2024"
    DataFrequency <- "Monthly"
    UnitMatYields <- "Month"

    # B.1) Decide on specific model inputs
    #################################### GVAR-based models ##################################################
    t_First_Wgvar <- "2004"
    t_Last_Wgvar <-  "2019"
    W_type <- 'Sample Mean'
    VARXtype <- "unconstrained"
    #################################### JLL-based models ###################################################
    DomUnit <- "China"
    WishSigmas <- 0
    SigmaNonOrtho <- NULL
    JLLModelType <- ModelType
    ###################################### BRW inputs  ######################################################
    flag_mean <- TRUE
    gamma <- 0.001
    N_iter <- 200
    N_burn <- N_iter*0.15
    B <- 50
    checkBRW <- 1
    B_check <- 1000
    #########################################################################################################

    # C) Decide on Settings for numerical outputs
    Horiz <- 25
    DesiredGraphs <- c("Fit", "GIRF", "GFEVD")
    WishGraphRiskFac <- 0
    WishGraphYields <- 1
    WishOrthoJLLgraphs <- 1

    # D) Bootstrap settings
    WishBootstrap <- 0
    Bootlist <- list()
    Bootlist$methodBS <- 'bs'
    Bootlist$BlockLength <- 4
    Bootlist$ndraws <-  1000
    Bootlist$pctg   <-  95

    # E) Out-of-sample forecast
    WishForecast <- 1
    ForecastList <- list()
    ForecastList$ForType <- "Rolling"
    ForecastList$ForHoriz <- 12
    ForecastList$t0Sample <- 1
    ForecastList$t0Forecast <- 100

    #########################################################################################################
    ############################### NO NEED TO MAKE CHANGES FROM HERE #######################################
    #########################################################################################################

    # 2) Minor preliminary work
    C <- length(Economies)
    FactorLabels <- LabFac(N, DomVar,GlobalVar, Economies, ModelType)
    ZZ <- RiskFactors

    Data <- list()
    Data$GVARFactors <- FactorsGVAR
    mat <- Maturities(Yields, Economies, UnitYields = UnitMatYields)

    # 2.1) Generate GVARinputs, JLLinputs and BRWinputs
    ModInputs <- ListModelInputs(ModelType, Data, Economies, VARXtype, t_First_Wgvar, t_Last_Wgvar, W_type,
                                 DomUnit, WishSigmas, SigmaNonOrtho, BiasCorrection, flag_mean, gamma,
                                 N_iter, N_burn, B, checkBRW, B_check)

    GVARinputs <- ModInputs$GVARinputs
    JLLinputs <- ModInputs$JLLinputs
    BRWinputs <- ModInputs$BRWinputs

    # 3) Prepare the inputs of the likelihood function
    ModelParaList <- list()

    # 3.1) Compute the inputs that go directly into the log-likelihood function
    ATSMInputs <- InputsForMLEdensity(ModelType, Yields, ZZ, FactorLabels, mat, Economies, DataFrequency,
                                      JLLinputs, GVARinputs, BRWinputs)

    # 3.2) Initial guesses for Variables that will be concentrared out of from the log-likelihood function
    K1XQ <- ATSMInputs$K1XQ
    if (ModelType == "JLL original"){ SSZ <- NULL}else{SSZ <- ATSMInputs$SSZ}

    # 4) Build the objective function
    f <- Functionf(ATSMInputs, Economies, mat, DataFrequency, FactorLabels, ModelType)

    # 5) Set the optimization settings
    VarLab <- ParaLabels(ModelType, StationarityUnderQ)

    varargin <- list()
    varargin$K1XQ <-list(K1XQ, VarLab[[ModelType]][["K1XQ"]] , NULL , NULL)
    varargin$SSZ <- list(SSZ, VarLab[[ModelType]][["SSZ"]], NULL, NULL)
    varargin$r0 <- list(NULL, VarLab[[ModelType]][["r0"]], NULL, NULL)
    varargin$se <- list(NULL, VarLab[[ModelType]][["se"]], 1e-6, NULL)
    varargin$K0Z <- list(NULL, VarLab[[ModelType]][["K0Z"]], NULL, NULL)
    varargin$K1Z <- list(NULL, VarLab[[ModelType]][["K1Z"]], NULL, NULL)
    varargin$OptRun <-  c("iter off")

    LabelVar<- c('Value', 'Label', 'LB', 'UB')
    for (d in 1:(length(varargin)-1)){ names(varargin[[d]]) <-  LabelVar}

    tol <- 1e-4
    # 6) Optimization of the model
    ModelParaList[[ModelType]] <- Optimization(f, tol, varargin, FactorLabels, Economies, ModelType,
                                               JLLinputs, GVARinputs)$Summary

    # 7) Numerical Outputs
    InputsForOutputs <- InputsForOutputs(ModelType, Horiz, DesiredGraphs, OutputLabel, StationarityUnderQ,
                                         UnitMatYields, WishGraphYields, WishGraphRiskFac, WishOrthoJLLgraphs,
                                         WishForwardPremia, FPmatLim, WishBootstrap, Bootlist, WishForecast,
                                         ForecastList)
    # A) Fit, IRF, FEVD, GIRF, GFEVD and Risk premia
    NumericalOutputs <- NumOutputs(ModelType, ModelParaList, InputsForOutputs, FactorLabels, Economies)

    # B) Bootstrap
    Bootstrap <- Bootstrap(ModelType, ModelParaList, NumericalOutputs, mat, Economies, InputsForOutputs,
                           FactorLabels, DataFrequency, varargin, JLLinputs, GVARinputs, BRWinputs)

    # C) Out-of-sample forecasting
    Forecasts <- ForecastYields(ModelType, ModelParaList, InputsForOutputs, FactorLabels, Economies,
                                DataFrequency, JLLinputs, GVARinputs, BRWinputs)

# 3 Candelon and Moura (2023)

In this paper, Candelon and Moura (2023) delve into an exploration of the underlying factors that shape the sovereign yield curves of Brazil, India, Mexico, and Russia in the midst of the COVID\(-19\) pandemic crisis. To comprehensively address the intricate web of global macro-financial and particularly health-related interdependencies, the study employs a modeling approach based on a GVAR jointQ type framework. By delving into these aspects, the authors aim to provide a nuanced understanding of the dynamics influencing sovereign yield curves in these countries during the challenging circumstances of the pandemic.

    # A) Load database data
    data("CM_Factors_2023")
    data('CM_Factors_GVAR_2023')
    data('CM_Trade_2023')
    data('CM_Yields_2023')

    # B) Decide on general model inputs
    ModelType <- "GVAR jointQ"

    StationarityUnderQ <- 0
    BiasCorrection <- 0

    WishForwardPremia <- 1
    FPmatLim <- c(47,48)

    Economies <- c("Brazil", "India", "Russia", "Mexico") # Names of the economies from the economic system
    GlobalVar <- c("US_Output_growth", "China_Output_growth", "SP500") # Global Variables
    DomVar <- c("Inflation","Output_growth", "CDS", "COVID") # Country-specific variables

    N <- 2 # Number of spanned factors per country

    OutputLabel <- "CM_2023"
    DataFrequency <- "Weekly"
    UnitMatYields <- "Month"

    # C.1) Decide on specific model inputs
    #################################### GVAR-based models ##################################################
    t_First_Wgvar <- "2015"
    t_Last_Wgvar <-  "2020"
    W_type <- 'Sample Mean'
    VARXtype <- "constrained: COVID"
    ###################################### BRW inputs  ######################################################

    # D) Decide on Settings for numerical outputs
    Horiz <- 12
    DesiredGraphs <- c("GIRF", "GFEVD", "TermPremia")
    WishGraphRiskFac <- 0
    WishGraphYields <- 1
    WishOrthoJLLgraphs <- 0

    # E) Bootstrap settings
    WishBootstrap <- 0 #  YES: 1; No = 0.
    Bootlist <- list()
    Bootlist$methodBS <- 'bs'
    Bootlist$BlockLength <- 4 # necessary input if one chooses the block bootstrap
    Bootlist$ndraws <-  100
    Bootlist$pctg   <-  95 # confidence level

    # F) Out-of-sample forecast
    WishForecast <- 0
    ForecastList <- list()
    ForecastList$ForHoriz <- 12 # forecast horizon
    ForecastList$t0Sample <- 1 # initial sample date
    ForecastList$t0Forecast <- 50 # last sample date for the first forecast
    ForecastList$ForType <- c()

    ##########################################################################################################
    ############################### NO NEED TO MAKE CHANGES FROM HERE ########################################
    ##########################################################################################################
    # 2) Minor preliminary work
    C <- length(Economies)
    FactorLabels <- LabFac(N, DomVar,GlobalVar, Economies, ModelType)
    ZZ <- RiskFactors

    Data <- list()
    Data$GVARFactors <- GVARFactors
    Data$Wgvar <-  Trade_Flows
    mat <- Maturities(Yields, Economies, UnitYields = UnitMatYields)

    # 2.1) Generate GVARinputs, JLLinputs and BRWinputs
    ModInputs <- ListModelInputs(ModelType, Data, Economies, VARXtype, t_First_Wgvar, t_Last_Wgvar, W_type)

    GVARinputs <- ModInputs$GVARinputs
    JLLinputs <- NULL

    # 3) Prepare the inputs of the likelihood function
    # 3.1) Compute the inputs that go directly into the log-likelihood function
    ATSMInputs <- InputsForMLEdensity(ModelType, Yields, ZZ, FactorLabels, mat, Economies, DataFrequency,
                                      JLLinputs, GVARinputs)

    # 3.2) Initial guesses for Variables that will be concentrared out of from the log-likelihood function
    K1XQ <- ATSMInputs$K1XQ
    SSZ <- ATSMInputs$SSZ

    # 4) Build the objective function
    f <- Functionf(ATSMInputs, Economies, mat, DataFrequency, FactorLabels, ModelType)

    # 5) Set the optimization settings
    VarLab <- ParaLabels(ModelType, StationarityUnderQ)

    varargin <- list()
    varargin$K1XQ <-list(K1XQ, VarLab[[ModelType]][["K1XQ"]] , NULL , NULL)
    varargin$SSZ <- list(SSZ, VarLab[[ModelType]][["SSZ"]], NULL, NULL)
    varargin$r0 <- list(NULL, VarLab[[ModelType]][["r0"]], NULL, NULL)
    varargin$se <- list(NULL, VarLab[[ModelType]][["se"]], 1e-6, NULL)
    varargin$K0Z <- list(NULL, VarLab[[ModelType]][["K0Z"]], NULL, NULL)
    varargin$K1Z <- list(NULL, VarLab[[ModelType]][["K1Z"]], NULL, NULL)
    varargin$OptRun <-  c("iter off")

    LabelVar<- c('Value', 'Label', 'LB', 'UB') # Elements of each parameter
    for (d in 1:(length(varargin)-1)){ names(varargin[[d]]) <-  LabelVar}

    tol <- 1e-4
    # 6) Optimization of the model
    ModelParaList <- list()
    ModelParaList[[ModelType]] <- Optimization(f, tol, varargin, FactorLabels, Economies, ModelType,
                                               JLLinputs, GVARinputs)$Summary

    # 7) Numerical Outputs
    InputsForOutputs <- InputsForOutputs(ModelType, Horiz, DesiredGraphs, OutputLabel, StationarityUnderQ,
                                         UnitMatYields, WishGraphYields, WishGraphRiskFac, WishOrthoJLLgraphs,
                                         WishForwardPremia, FPmatLim, WishBootstrap, Bootlist, WishForecast,
                                         ForecastList)
    # A) Fit, IRF, FEVD, GIRF, GFEVD, and Term Premia
    NumericalOutputs <- NumOutputs(ModelType, ModelParaList, InputsForOutputs, FactorLabels, Economies)

    # B) Bootstrap
    Bootstrap <- Bootstrap(ModelType, ModelParaList, NumericalOutputs, mat, Economies, InputsForOutputs,
                           FactorLabels, DataFrequency, varargin, JLLinputs, GVARinputs)

# References

Ang, Andrew, and Monika Piazzesi. 2003. “A No-Arbitrage Vector Autoregression of Term Structure Dynamics with Macroeconomic and Latent Variables.” Journal of Monetary Economics 50 (4): 745–87.
Bauer, Michael D, and Glenn D Rudebusch. 2017. “Resolving the Spanning Puzzle in Macro-Finance Term Structure Models.” Review of Finance 21 (2): 511–53.
Candelon, Bertrand, and Rubens Moura. Forthcoming. “A Multicountry Model of the Term Structures of Interest Rates with a GVAR.” Journal of Financial Econometrics, Forthcoming.
———. 2023. “Sovereign Yield Curves and the COVID-19 in Emerging Markets.” Economic Modelling, 106453. https://doi.org/https://doi.org/10.1016/j.econmod.2023.106453.
Joslin, Scott, Marcel Priebsch, and Kenneth J. Singleton. 2014. “Risk Premiums in Dynamic Term Structure Models with Unspanned Macro Risks.” Journal of Finance 69 (3): 1197–1233.
Jotikasthira, Chotibhak, Anh Le, and Christian Lundblad. 2015. “Why Do Term Structures in Different Currencies Co-Move?” Journal of Financial Economics 115: 58–83.