No post de hoje iremos construir um código em R para analisar o impulso resposta em séries financeiras, especificadamente a resposta do IBOVESPA a um choque de um desvio padrão na SELIC.
VAR e IRF
A função de impulso resposta (FIR) é utilizada para obter uma visão do comportamento dinâmico de um modelo. De maneira simplificada, utiliza-se um VAR para representar que cada variável em seu sistema possa ser explicada por sua média e pela soma de choques com pesos associados, sendo que cada peso representa os choques nas variáveis. Por meio de diversos métodos é possível usar tais pesos para computar o efeito de uma unidade de aumento de inovação da variável em determinado tempo sobre outra variável em um tempo futuro, mantendo todas as outras inovações e tempos constantes.
Variáveis
Como exemplo, criaremos um VAR definido de acordo com o trablaho de Nunes etl al. (2005), com algumas modificações. O objetivo é avaliar as inter-relações de variáveis macroeconomicas e financeiras através do uso de funções impulso resposta. As variáveis escolhidas são:
- EMBI+ Risco-Brasil
- Ibovespa - Índice de ações - Fechamento
- PIB mensal - Valores correntes
- Taxa de câmbio real bilateral - IPA-DI - BR/US
- Taxa de juros - Selic acumulada no mês anualizada base 252
- Índice Nacional de Preços ao Consumidor Amplo (IPCA)
Vamos utilizar os seguintes pacotes para criar o modelo VAR e avaliar o FIR.
library(magrittr) library(GetBCBData) library(ipeadatar) library(lubridate) library(tidyr) library(dplyr) library(tsibble) library(purrr) library(forecast) library(ggplot2) library(vars)
Coleta e Tratamento
Iremos coletar os dados de diferentes fontes, utilizando o código abaixo.
# |-- Coleta e pré tratamento --|
# PIB mensal - Valores correntes - R$ milhões (BCB)
# Taxa de juros - Selic acumulada no mês anualizada base 252 - % a.a.
# Índice Nacional de Preços ao Consumidor Amplo (IPCA) - % a.m.
df_bcb <- GetBCBData::gbcbd_get_series(
id = c(
"pib_mensal" = 4380,
"selic" = 4189,
"ipca" = 433
),
first.date = lubridate::ymd("2003-12-01"),
use.memoise = FALSE
) %>%
tidyr::pivot_wider(
id_cols = "ref.date",
names_from = "series.name",
values_from = "value"
) %>%
dplyr::rename("date" = "ref.date") %>%
dplyr::mutate(date = tsibble::yearmonth(.data$date))
# Taxa de câmbio real bilateral - IPA-DI - BR/US: índice (média 2010 = 100)
# Ibovespa - Índice de ações - Fechamento - Anbima - % a.m.
# EMBI+ Risco-Brasil - ponto-base
# Índice Nacional de Preços ao Consumidor Amplo (IPCA) - Índice (dez. 1993 = 100)
codes_ipea <- c(
"ibovespa" = "ANBIMA12_IBVSP12",
"cambio_real" = "GAC12_TCEREUA12",
"embi_br" = "JPM366_EMBI366",
"ipca_indice" = "PRECOS12_IPCA12"
)
df_ipea <- ipeadatar::ipeadata(codes_ipea) %>%
tidyr::pivot_wider(
id_cols = "date",
names_from = "code",
values_from = "value"
) %>%
dplyr::select("date", dplyr::all_of(codes_ipea)) %>%
dplyr::group_by(date = tsibble::yearmonth(.data$date)) %>%
dplyr::summarise(
dplyr::across(
.cols = !dplyr::any_of("date"),
.fns = ~mean(.x, na.rm = TRUE)
),
.groups = "drop"
)
# |-- Cruzar tabelas --|
df_fin_macro <- dplyr::left_join(
x = df_ipea,
y = df_bcb,
by = "date"
) %>%
dplyr::filter(lubridate::as_date(date) >= lubridate::ymd("2003-12-01")) %>%
tidyr::drop_na()
Deflacionaremos os dados do PIB mensal, do IBOVESPA e da SELIC.
# Deflacionamento ---------------------------------------------------------
# Deflacionar séries nominais (note que para a SELIC é mais apropriado a
# equação de Fisher, mas optamos por simplificar)
df_fin_macro %<>%
dplyr::mutate(
dplyr::across(
.cols = c("pib_mensal", "ibovespa", "selic"),
.fns = ~ipca_indice[date == dplyr::last(date)] / ipca_indice * .x
)
) %>%
dplyr::select(-"ipca_indice")
Estacionariedade e Diferenciação
Antes de construir o VAR, é necessário certificar que estamos utilizando variáveis estacionárias, para isso, usamos a função constituída abaixo para aplicar os testes ADF, KPSS e PP. Caso houver variáveis não estacionárias, realizaremos as suas respectivas diferenciações em seguida.
#' Report number of differences to make time series stationary (vectorized)
#'
#' @param x List-like object with vectors of the series to be tested
#' @param test Type of unit root test to use, see forecast::ndiffs
#' @param term Specification of the deterministic component in the regression, see forecast::ndiffs
#' @param alpha Level of the test, possible values range from 0.01 to 0.1
#' @param na_rm Remove NAs from x?
#'
#' @return Tibble with variable name from x and the number of differences found
#' @export
report_ndiffs <- function (
x,
test = c("kpss", "adf", "pp"),
term = c("level", "trend"),
alpha = 0.05,
na_rm = TRUE
) {
# All possible tests and terms
ndiffs_tests <- purrr::cross(list(test = test, type = term))
ndiffs_tests <- purrr::set_names(
x = ndiffs_tests,
nm = paste(
purrr::map_chr(ndiffs_tests, 1),
purrr::map_chr(ndiffs_tests, 2),
sep = "_"
)
)
# Nested for-loop
purrr::map(
.x = if (na_rm) {stats::na.omit(x)} else x,
.f = ~purrr::map(
.x = ndiffs_tests,
.f = function (y) {
forecast::ndiffs(
x = .x,
alpha = alpha,
test = y[[1]],
type = y[[2]]
)
}
)
) %>%
purrr::map_df(dplyr::bind_rows, .id = "variable") %>%
# Create column with most frequent value to differentiate
dplyr::rowwise() %>%
dplyr::mutate(
ndiffs = dplyr::c_across(!dplyr::any_of("variable")) %>%
table() %>%
sort(decreasing = TRUE) %>%
names() %>%
purrr::chuck(1) %>%
as.numeric()
) %>%
dplyr::ungroup()
}
Após a construção da função, a aplicamos nos dados e fazemos a diferenciação.
# Estacionariedade -------------------------------------------------------- # Testes (ADF, PP, KPSS) p/ obter nº de differenças p/ a série ser estacionária vars_ndiffs <- df_fin_macro %>% dplyr::select(-"date") %>% report_ndiffs() # Diferenciar séries para obter estacionariedade df_fin_macro %<>% dplyr::mutate( dplyr::across( .cols = vars_ndiffs$variable[vars_ndiffs$ndiffs > 0], .fns = ~tsibble::difference( x = .x, differences = vars_ndiffs$ndiffs[vars_ndiffs$variable == dplyr::cur_column()] ) ) ) %>% tidyr::drop_na()
Visualização das variáveis
Com os dados tratados, visualizamos em um gráfico o resultado das séries.
# Visualização de dados --------------------------------------------------- # Gráfico de linhas da séries df_fin_macro %>% tidyr::pivot_longer(-"date") %>% ggplot2::ggplot() + ggplot2::aes(x = lubridate::as_date(date), y = value) + ggplot2::geom_line() + ggplot2::facet_wrap(~name, scales = "free")
Construindo o VAR
Para criar o modelo VAR, é possível realizar a seleção de defasagens por critérios de informação por meio da função VARselect do pacote {vars}. Com a quantidade defasagem definidas, é possível enfim estimar o modelo VAR com a função VAR do pacote {vars}.
# Seleção de defasagens VAR por critérios de informação lags_var <- vars::VARselect( y = df_fin_macro[-1], lag.max = 12, type = "const" ) # Estimar modelo VAR fit_var <- vars::VAR( y = df_fin_macro[-1], p = lags_var$selection["AIC(n)"], type = "const", lag.max = 12, ic = "AIC" )
Construindo o IRF
Com o resultado, avaliamos o impulso reposta por meio da função irf do pacote {vars} e averiguamos o resultado por meio de um gráfico. Avaliaremos um choque na SELIC e a resposta no IBOVESPA.
# Obter os coeficientes de impulso resposta do VAR
# Exemplo 1: choque na SELIC e resposta no IBOVESPA
irf_var <- vars::irf(
x = fit_var,
impulse = "selic",
response = "ibovespa",
n.ahead = 12
)
# Plotar gráfico de impulso resposta
lags = 1:13
df_irf <- data.frame(irf = irf_var$irf, lower = irf_var$Lower, upper = irf_var$Upper,
lags = lags)
colnames(df_irf) <- c('irf', 'lower', 'upper', 'lags')
number_ticks <- function(n) {function(limits) pretty(limits, n)}
ggplot(data = df_irf,aes(x=lags,y=irf)) +
geom_line(aes(y = upper), colour = 'lightblue2') +
geom_line(aes(y = lower), colour = 'lightblue')+
geom_line(aes(y = irf), size=.8)+
geom_ribbon(aes(x=lags, ymax=upper,
ymin=lower),
fill="blue", alpha=.1) +
xlab("") + ylab("IBOVESPA") +
ggtitle("Resposta ao Impulso na SELIC") +
theme(axis.title.x=element_blank(),
axis.text.x=element_blank(),
axis.ticks.x=element_blank(),
plot.margin = unit(c(2,10,2,10), "mm"))+
geom_line(colour = 'black')+
scale_x_continuous(breaks=number_ticks(13))+
theme_bw()
Interpretação
Dado um choque de um desvio padrão na variável SELIC do modelo a variável IBOVESPA do modelo (retornos) diminuirá em cerca de 1,78 no primeiro período, dado que o coeficiente é significativo (intervalos de confiança fora do zero) ou seja, a interpretação é na mesma unidade da variável, como especificada no modelo... se o modelo estivesse especificado em log, a interpretação seria %.
________________________________________________
Quer se aprofundar no assunto?
Alunos da trilha de Ciência de dados para Economia e Finanças possuem acesso o curso Analise de dados Macroeconômicos e Financeiros e podem aprender a como construir projetos que envolvem dados reais usando modelos econométricos e de Machine Learning com o R.
________________________________________________
Referências
Nunes, M. S., da Costa Jr, N. C., & Meurer, R. (2005). A relação entre o mercado de ações e as variáveis macroeconômicas: uma análise econométrica para o Brasil. Revista Brasileira de Economia, 59(4), 585-607.

