Econometria Aplicada - Exercício 1

Autor

Leonardo Zanetti

Data de Publicação

31 de agosto de 2025

1 Introdução

Em modelos VAR estruturais (SVAR), o objetivo é decompor os movimentos das variáveis em choques estruturais com interpretação econômica (por exemplo, um choque de política monetária). Partimos do VAR reduzido e da sua matriz de covariância dos resíduos; o desafio de identificação surge porque múltiplas decomposições ortogonais dessa covariância são possíveis, levando a diferentes mapas entre resíduos (reduzidos) e choques (estruturais). Em macroeconomia, essa identificação é crucial para interpretar funções impulso-resposta (IRFs) como efeitos causais e, assim, avaliar mecanismos e políticas.

Duas estratégias comuns são: (i) identificação recursiva via decomposição de Cholesky e (ii) restrições de sinais (Uhlig, 2005).

  • Identificação recursiva (Cholesky): impõe uma ordenação das variáveis e zera alguns efeitos contemporâneos. Em termos práticos, assume que certas variáveis não reagem instantaneamente a outras dentro do mesmo período. Pontos positivos: simples, transparente e fácil de implementar. Pontos negativos: sensível à ordenação escolhida e impõe restrições de tempo/zeros potencialmente fortes.

  • Restrições de sinais (Uhlig, 2005): em vez de zeros contemporâneos, impõe-se que as IRFs de determinadas variáveis tenham sinais específicos por alguns períodos após o choque (por exemplo, um aperto monetário eleva a taxa de juros e reduz inflação e produto por alguns trimestres). Procura-se uma decomposição que satisfaça essas restrições, usualmente por amostragem sobre rotações ortogonais. Pontos positivos: evita hipóteses rígidas de ordenação/zeros e permite incorporar conhecimento teórico mais fraco. Pontos negativos: identificação em conjunto (conjuntos de soluções), intervalos potencialmente amplos e resultados dependentes da escolha de sinais e janelas.

Comparar as duas abordagens é útil porque elas refletem suposições diferentes sobre a dinâmica contemporânea e sobre o conteúdo informacional das respostas. Em particular, Uhlig (2005) reporta que um choque contracionista aumenta juros e reduz inflação como esperado, mas os efeitos sobre o produto podem surpreender; aqui investigaremos a robustez desse resultado sob diferentes especificações e variáveis no VAR.

Esse documento está estruturado de forma a apresentar os códigos construídos para cada etapa do exercício à medida que avançamos na análise. A seguir, detalhamos os dados, a metodologia (VAR reduzido, Cholesky e restrições de sinais), os resultados (IRFs e análises de robustez), discussão e conclusão.

# Carregando os pacotes necessários (conferir Apêndice para instalação)

library(vars)
library(VARsignR)
library(readxl)
library(ggplot2)
library(dplyr)
library(tidyr)
library(tseries)

# Seeding para reprodutibilidade

set.seed(42)

2 Dados

Utilizamos dados trimestrais para os EUA (1965.Q1–2005.Q4), consistentes com a base utilizada em Uhlig (2005) e disponibilizada no curso. O conjunto inclui: PIB real (GDP), deflator implícito do PIB (Deflator), índice de preços ao produtor para commodities (Commodity), taxa efetiva dos federal funds (FFD), reservas totais e não tomadas emprestadas das instituições depositárias (TotReserves, NonReserves), consumo real (Consumption), investimento privado doméstico real (Investment) e o spread entre o rendimento de títulos corporativos Aaa e o Treasury de 10 anos (spread). O spread está disponível a partir de 1983.Q1. Para descrição agregada rápida, reportamos abaixo estatísticas sumárias da base carregada. Em termos de transformações, adotaremos log das variáveis em nível real e de preços (rgdp, pgdp, pcomm_sa, rcons, rinv) e manteremos em porcentagem as variáveis já em taxa/nível percentual (ff, spread). Eventuais ajustes adicionais (dessazonalização, diferenciação para estacionariedade) serão discutidos na etapa de pré-processamento do VAR.

# Carregamento e descrição básica dos dados

df <- read_excel("../references/data_ea1_uhlig.xlsx")

summary(df)
     dates           GDP           Deflator       Commodity     
 Min.   :1965   Min.   : 4062   Min.   :18.34   Min.   : 31.87  
 1st Qu.:1975   1st Qu.: 5701   1st Qu.:30.57   1st Qu.: 57.80  
 Median :1985   Median : 7953   Median :56.55   Median :102.73  
 Mean   :1985   Mean   : 8500   Mean   :53.48   Mean   : 92.78  
 3rd Qu.:1996   3rd Qu.:10683   3rd Qu.:74.67   3rd Qu.:123.85  
 Max.   :2006   Max.   :15067   Max.   :91.98   Max.   :163.58  
                                                                
      FFD          TotReserves     NonReserves     Consumption   
 Min.   : 0.980   Min.   :21.26   Min.   :20808   Min.   : 2466  
 1st Qu.: 4.525   1st Qu.:34.69   1st Qu.:34246   1st Qu.: 3594  
 Median : 5.690   Median :41.00   Median :39944   Median : 5114  
 Mean   : 6.518   Mean   :42.15   Mean   :41408   Mean   : 5492  
 3rd Qu.: 8.398   3rd Qu.:49.65   3rd Qu.:49065   3rd Qu.: 6957  
 Max.   :19.100   Max.   :62.67   Max.   :60953   Max.   :10175  
                                                                 
   Investment         spread       
 Min.   : 508.5   Min.   :-0.0900  
 1st Qu.: 739.0   1st Qu.: 0.8375  
 Median :1130.3   Median : 1.0400  
 Mean   :1238.5   Mean   : 1.1451  
 3rd Qu.:1543.7   3rd Qu.: 1.4500  
 Max.   :2743.8   Max.   : 2.5700  
                  NA's   :72       

A Figura 1 apresenta as séries temporais já transformadas (isto é, já em log quando necessário).

# Grid de gráficos das séries

df <- df %>% 
  mutate(dates = as.numeric(dates),
         GDP = log(GDP),
         Deflator = log(Deflator),
         Commodity = log(Commodity),
         Consumption = log(Consumption),
         Investment = log(Investment),
         NonReserves = log(NonReserves),
         TotReserves = log(TotReserves))

df_long <- df %>%
  pivot_longer(cols = -dates, names_to = "variavel", values_to = "valor")

plot1 <- ggplot(df_long, aes(x = dates, y = valor)) +
  geom_line(color = "black") +
  facet_wrap(~ variavel, scales = "free_y", ncol = 3) +
  theme_bw() +
  labs(x = "Tempo", y = "Valor")

plot1

Figura 1: Séries temporais

É importante notar que a variável de spread bancário possui dados ausentes para o período anterior a 1983. Isso é bastante relevante, uma vez que a estimação do modelo com o spread implica a redução do tamanho da amostra e a análise de um período diferente do usado por Uhlig (2005).

3 Metodologia

Esse relatório possui dois objetivos. Em primeiro lugar, replicar os resultados de Uhlig (2005) e discutir os resultados de cada uma das abordagens de identificação (Cholesky e restrições de sinais). Em segundo lugar, explorar variações na especificação do VAR (número de defasagens, inclusão/exclusão de variáveis). Portanto, vamos estimar dois VARs em janelas temporais diferentes. O primeiro VAR será bastante próximo do modelo original, utilizando as mesmas variáveis e período (1965.Q1–2005.Q4), mas com 4 defasagens (em vez de 12, como no artigo original, que utiliza dados mensais). O segundo VAR será estimado a partir de 1983.Q1 (para incluir o spread bancário) e com a inclusão das variáveis de investimento e consumo. Para ambos os casos, verificaremos a estacionariedade dos resíduos do VAR reduzido antes de prosseguir para a identificação estrutural, que será feita via Cholesky e restrições de sinais também para ambos os VARs.

4 Resultados

4.1 Modelo original (1965.Q1 a 2005.Q4, sem spread, consumo e investimento)

4.1.1 VAR reduzido

df_var1 <- df %>% select(-c(dates, Consumption, Investment, spread))

var_model <- VAR(df_var1, p = 4, type = "none")

# Teste ADF nos resíduos (uma série por coluna)

residuos <- residuals(var_model)
adf_list <- lapply(as.data.frame(residuos), function(x) tseries::adf.test(x))
adf_table <- data.frame(
  variavel = names(adf_list),
  statistic = sapply(adf_list, function(r) unname(r$statistic)),
  p_value = sapply(adf_list, function(r) r$p.value),
  row.names = NULL
)

adf_table
     variavel statistic p_value
1         GDP -5.087838    0.01
2    Deflator -5.197799    0.01
3   Commodity -5.248986    0.01
4         FFD -4.053174    0.01
5 TotReserves -4.535321    0.01
6 NonReserves -4.623392    0.01

Com base na tabela de ADF acima, como os p-valores são inferiores a 1% para todas as séries de resíduos, rejeitamos a hipótese nula de raiz unitária. Portanto, os resíduos do VAR são estacionários. Com isso verificado, podemos prosseguir para as duas estratégias de identificação: a recursiva (Cholesky) e as restrições de sinais.

4.1.2 Identificação recursiva (Cholesky)

# Identificação recursiva (Cholesky) via VARsignR::rfbvar
# Choque de política monetária na taxa de juros (FFD)

# Convertendo os dfs para ts

df1 <- df %>% select(-c(Consumption, Investment, spread))
df1$dates <- as.yearqtr(df1$dates)

mat1 <- as.matrix(select(df1, -dates))

df1_ts <- ts(data = mat1,
            start = c(1965, 1),
            end = c(2005, 4),
            frequency = 4)

# Identificação 

model_chol <- rfbvar(Y = df1_ts,
                     nlags = 4,
                     draws = 1000,
                     constant = FALSE,
                     steps = 20,
                     shock = 4)

# IRFs

irfs_chol1 <- model_chol$IRFS

vl <- c("GDP", "GDP Deflator", "Comm.Pr.Index", "Fed Funds Rate",
        "Total Reserves", "Nonborrowed Reserves")

irfplot(irfdraws = irfs_chol1, type = "median", labels = vl,
        save = TRUE, bands = c(0.16, 0.84), grid = TRUE, bw = TRUE)

# Obs: o irfplot apenas desenha o gráfico, mas não retorna o objeto.
# Portanto, é necessário salvar a imagem para plotar.

IRFs - Cholesky (choque em FFD)

Esses resultados são bastante próximos dos que Uhlig consegue com dados mensais fazendo a decomposição de Cholesky. O choque contracionista eleva fortemente a FFD no impacto e a resposta decai gradualmente. Observa-se um price puzzle claro no GDP Deflator, com aumento persistente nos primeiros trimestres, apesar do aperto monetário. Comm.Pr.Index cai, e Nonborrowed Reserves recuam, enquanto Total Reserves exibem resposta mista (elevação inicial e queda subsequente). O GDP recua no curto prazo, como os modelos econômicos prevêem. Em suma, a identificação recursiva reproduz o price puzzle clássico e gera um impacto negativo na atividade.

4.1.3 Restrições de sinais (Uhlig, 2005)

# SVAR com restrições de sinais — modelo original (1965Q1–2005Q4)
# Ordem em df1_ts: GDP, Deflator, Commodity, FFD, Total Reserves, Nonborrowed Reserves
# Restrições (Uhlig, 2005, adaptado p/ dados trimestrais, janela 1–4):
#  1. PIB (sem restrição)
#  2. Deflator -
#  3. Comm Price -
#  4. Juros (primeira) +
#  5. Total reserves (sem restrição)
#  6. Nonborrowed reserves -
# Choque é no juros -> Primeira a especificar

constr1 <- c(+4, -2, -3, -6)

model_sign1 <- uhlig.reject(
  Y = df1_ts,
  nlags = 4,
  draws = 200,
  subdraws = 200,
  nkeep = 500,
  KMIN = 1,
  KMAX = 2,
  constrained = constr1,
  constant = FALSE,
  steps = 20
)

irfs_sign1 <- model_sign1$IRFS
vl1 <- c("GDP", "GDP Deflator", "Comm.Pr.Index", "Fed Funds Rate",
         "Total Reserves", "Nonborrowed Reserves")
irfplot(irfdraws = irfs_sign1, type = "median", labels = vl1,
        save = FALSE, bands = c(0.16, 0.84), grid = TRUE, bw = TRUE)

IRFs - Restrição de Sinal (choque em FFD)

As restrições eliminam o price puzzle por construção: GDP Deflator e Comm.Pr.Index caem após o choque e FFD sobe no impacto. O resultado mais controverso aparece no GDP: a contração é fraca e, em alguns horizontes, a resposta tende a zero ou mesmo levemente positiva, reproduzindo a evidência surpreendente de Uhlig (2005) de efeitos pouco negativos do aperto sobre o produto. Nonborrowed Reserves caem de forma pronunciada, coerente com contração monetária. Assim, as restrições corrigem o price puzzle, mas levam ao “resultado estranho” para o GDP. ### Modelo alternativo (1983.Q1 a 2005.Q4, com spread, consumo e investimento)

4.1.4 VAR reduzido – 1983.Q1 a 2005.Q4 (com spread, consumo e investimento)

df_var2 <- df %>% select(-c(dates)) %>% drop_na()

var_model <- VAR(df_var2, p = 4, type = "none")

# Teste ADF nos resíduos (uma série por coluna)

residuos <- residuals(var_model)
adf_list <- lapply(as.data.frame(residuos), function(x) tseries::adf.test(x))
adf_table <- data.frame(
  variavel = names(adf_list),
  statistic = sapply(adf_list, function(r) unname(r$statistic)),
  p_value = sapply(adf_list, function(r) r$p.value),
  row.names = NULL
)

adf_table
     variavel statistic p_value
1         GDP -5.427101    0.01
2    Deflator -4.222661    0.01
3   Commodity -5.059293    0.01
4         FFD -6.190668    0.01
5 TotReserves -5.418485    0.01
6 NonReserves -4.814872    0.01
7 Consumption -5.487023    0.01
8  Investment -4.853466    0.01
9      spread -5.566311    0.01

Novamente, a hipótese nula é rejeitada em todos os casos, indicando que os resíduos do VAR são estacionários. Isso nos permite prosseguir para as estratégias de identificação estrutural.

4.1.5 Identificação recursiva (Cholesky)

# Identificação recursiva (Cholesky) via VARsignR::rfbvar
# Choque de política monetária na taxa de juros (FFD)

# Convertendo os dfs para ts

df2 <- df %>% drop_na()
df2$dates <- as.yearqtr(df2$dates)

mat2 <- as.matrix(select(df2, -dates))

df2_ts <- ts(data = mat2,
            start = c(1983, 1),
            end = c(2005, 4),
            frequency = 4)

# Identificação 

model_chol2 <- rfbvar(Y = df2_ts,
                     nlags = 4,
                     draws = 1000,
                     constant = FALSE,
                     steps = 20,
                     shock = 4)

# IRFs

irfs_chol2 <- model_chol2$IRFS

vl <- c("GDP", "GDP Deflator", "Comm.Pr.Index", "Fed Funds Rate",
        "Total Reserves", "Nonborrowed Reserves", "Consumption", "Investment", "Spread")

irfplot(irfdraws = irfs_chol2, type = "median", labels = vl,
        save = TRUE, bands = c(0.16, 0.84), grid = TRUE, bw = TRUE)

IRFs - Cholesky (choque em FFD)

Com a janela pós‑1983 e inclusão de Consumption, Investment e Spread, a resposta da FFD é menos persistente. O GDP Deflator já não exibe price puzzle tão forte; a inflação tende a cair após o choque. Consumption e Investment caem no curto prazo e se normalizam lentamente, e o Spread aumenta (aperto financeiro). O GDP mostra queda pequena e transitória. A ampliação de variáveis e a mudança de amostra parecem mitigar o price puzzle sob Cholesky.

4.1.6 Restrições de sinais (Uhlig, 2005)

# SVAR com restrições de sinais — modelo alternativo (1983Q1–2005Q4)
# Ordem em df2_ts: GDP, Deflator, Commodity, FFD, Total Reserves, Nonborrowed Reserves, Consumption, Investment, Spread
# Restrições (choque monetário, janela 1–4):
#  1. PIB (sem restrição)
#  2. Deflator -
#  3. Comm Price -
#  4. Juros (primeira) +
#  5. Total reserves (sem restrição)
#  6. Nonborrowed reserves -
#  7. Consumption (sem restrição)
#  8. Investment (sem restrição)
# Choque é no juros -> Primeira a especificar

constr2 <- c(+4, -2, -3, -6)

model_sign2 <- uhlig.reject(
  Y = df2_ts,
  nlags = 4,
  draws = 200,
  subdraws = 200,
  nkeep = 500,
  KMIN = 1,
  KMAX = 2,
  constrained = constr2,
  constant = FALSE,
  steps = 20
)

irfs_sign2 <- model_sign2$IRFS
vl2 <- c("GDP", "GDP Deflator", "Comm.Pr.Index", "Fed Funds Rate",
         "Total Reserves", "Nonborrowed Reserves", "Consumption", "Investment", "Spread")
irfplot(irfdraws = irfs_sign2, type = "median", labels = vl2,
        save = FALSE, bands = c(0.16, 0.84), grid = TRUE, bw = TRUE)

IRFs - Restrição de Sinal (choque em FFD)

As restrições novamente garantem queda de GDP Deflator e Comm.Pr.Index e aumento de FFD no impacto. Nonborrowed Reserves caem, e o Spread sobe, ambos consistentes com aperto monetário. Em linha com o caso replicado, o GDP permanece com resposta fraca e, por vezes, próxima de zero, reforçando o achado “agnóstico” de Uhlig de efeitos pouco negativos sobre o produto mesmo quando o price puzzle é resolvido. Consumption e Investment caem no curto prazo, mas a contração é moderada.

5 Conclusão

Este exercício estimou dois modelos VAR trimestrais com 4 defasagens e sem constante para estudar os efeitos de choques monetários: (i) um modelo “original” (1965.Q1–2005.Q4) alinhado a Uhlig (2005), e (ii) um modelo “alternativo” (1983.Q1–2005.Q4) com inclusão de consumo, investimento e spread. Em ambos, verificamos a estacionariedade dos resíduos (ADF) antes da identificação estrutural via (a) Cholesky e (b) restrições de sinais (janela curta 1–2 trimestres), com choque na taxa de juros (FFD).

No modelo original com Cholesky, reproduzimos o price puzzle: o deflator sobe após um aperto monetário. O PIB recua pouco e gradualmente. Com restrições de sinais no modelo original, o price puzzle é eliminado por construção (inflação e commodities caem), mas o PIB mostra resposta fraca/próxima de zero, replicando o achado “surpreendente” de Uhlig (2005). No modelo 1983–2005 com Cholesky, o price puzzle é muito atenuado: a inflação cai, o spread sobe e PIB/consumo/investimento recuam moderadamente. Com restrições de sinais no modelo 1983–2005, o padrão teórico é reforçado (inflação/commodities caem, reservas não‑tomadas emprestadas recuam, spread sobe), enquanto o efeito sobre o PIB permanece pequeno.

Em síntese, as restrições de sinais corrigem o price puzzle observado com Cholesky, mas implicam respostas modestas do produto — resultado robusto às especificações analisadas. A mudança de amostra e a inclusão de variáveis financeiras também mitigam o price puzzle sob Cholesky. Extensões naturais incluem: verificar janelas alternativas de restrição, diferentes ordenações/priors, e explorar especificações com medidas adicionais do canal de crédito.

6 Referências

Uhlig, H. (2005). What are the effects of monetary policy on output? Results from an agnostic identification procedure. Journal of Monetary Economics, 52, 381–419.

7 Apêndice: Script de instalação de pacotes

A instalação do pacote VARsignR requer o pacote minqa, que por sua vez depende do mvnfast. O pacote HI também é necessário para algumas funções auxiliares. Ambos os pacotes não estão disponíveis no CRAN, mas podem ser instalados a partir dos arquivos .tar.gz fornecidos na pasta packages/, que foram baixados diretamente do endereço do GitHub correspondente a cada pacote.

# Script para instalação dos pacotes necessários para o projeto
# Execute este script ANTES de renderizar o documento Quarto

# Configurar repositório CRAN
options(repos = c(CRAN = "https://cran.rstudio.com/"))

# Instalar pacotes do CRAN
install.packages("vars")
install.packages("minqa")
install.packages("mvnfast")

# Instalar pacotes locais (certifique-se de que os arquivos .tar.gz estão na pasta packages/)
install.packages("packages/HI_0.5_fixed3.tar.gz", repos = NULL, type = "source")
install.packages("packages/VARsignR_0.1.2.tar.gz", repos = NULL, type = "source")

# Verificar se os pacotes foram instalados corretamente
library(vars)
library(minqa)
library(mvnfast)
library(HI)
library(VARsignR)

cat("Todos os pacotes foram instalados com sucesso!\n")