Na próxima quinta-feira, 22 de fevereiro, será divulgada, pelo COPOM (Comitê de Política Monetária), o novo valor para a meta da taxa SELIC. Há uma expectativa de que o COPOM reduza em 0.75% a SELIC, mantendo a redução divulgada na última reunião, em 11 de janeiro. Obviamente esta expectativa de redução não é consenso no mercado, há os que acreditam em uma redução mais moderada, de 0.50%, assim como os que acreditam em uma redução de 1.00%.
Há uma forma de obter esta expectativa a partir dos contratos futuros de taxas de juros negociados na BM&FBovespa. A taxa de juros CDI, divulgada pela CETIP, acompanha os movimentos da SELIC, de forma que uma redução na SELIC implica em uma redução no CDI. Na BM&FBovespa são negociados contratos futuros sobre o CDI (são os futuros de DI1—CDI de 1 dia) e nestes contratos está implícita a expectativa dos movimentos futuros da taxa CDI, logo, está implícito nestes contratos as expectativas de intervenções do COPOM.
Vou mostrar neste post as relações entre CDI e SELIC e como observar as expectativas de interveções do COPOM na SELIC presentes nos contrtos futuros de DI1.
Começemos carregando os pacotes utilizados.
library(rbmfbovespa)
library(dplyr)
library(tidyr)
library(ggplot2)
library(ggthemes)
theme_set(theme_fivethirtyeight())
Trago neste post uma novidade, o uso do pacote ggthemes para enriquecer a visualização. Neste pacote há diversos temas para ggplot que incluem: excel, wall street journal, five thirty eight e outros. Aqui vou usar o tema do FiveThirtyEight.
Para realizar esta análise foram necessários diversos arquivos da BM&FBovespa, para diversas datas, por isso fiz as funções abaixo para baixar os arquivos do FTP público da BM&FBovespa e carregar os datasets.
download_rbmfbovespa <- function(url) {
fdest_dir <- tempdir()
fdest <- tempfile(tmpdir = fdest_dir)
ix <- download.file(url, fdest, quiet = TRUE)
if (ix != 0)
stop('Download problems: code = ', ix, ' url = ', url)
unz_fname <- unzip(fdest, exdir = fdest_dir)
# return unzipped file name
unz_fname
}
download_and_read <- function(x, url, file_template, rbmfbovespa_template) {
url_template <- file.path(url, file_template)
url <- sprintf(url_template, format(x, '%y%m%d'))
unz_fname <- try(download_rbmfbovespa(url))
if (is(unz_fname, 'try-error'))
return(NULL)
read_marketdata(unz_fname, template = rbmfbovespa_template)
}
Eu carrego os dados desde dezembro de 2016, para mostrar o efeito nos contratos futuros que com e sem expectativas de mudança na taxa básica de juros.
Para definir as data de download eu utilizo a função bizseq
do pacote bizdays para pegar apenas os dias útes, que no mercado brasileiro estão no calendário divulgado pela ANBIMA, por isso uso o calendário 'Brazil/ANBIMA'
em bizdays.
Infelizmente existem duas datas neste calendário em que não foram publicados arquivos, são os dias: 31 de dezembro e 25 de janeiro, pois são dias em que não há negociação na Bolsa, mas estão presentes no calendário Brazil/ANBIMA por serem dias em que há divulgação da taxa SELIC pelo Banco Central.
Para executar o download nas datas definidas eu utilizo a função map
do purrr, que funciona exatamente como lapply
.
Em seguida uso a função compact
para remover os elementos com NULL
que foram gerados pelas datas que não possuiam arquivos.
dates <- bizdays::bizseq('2016-12-01', '2017-02-17', 'Brazil/ANBIMA')
indics <- purrr::map(dates, download_and_read, 'ftp://ftp.bmf.com.br/IndicadoresEconomicos', 'ID%s.ex_', 'Indic')
bd_finals <- purrr::map(dates, download_and_read, 'ftp://ftp.bmf.com.br/ContratosPregaoFinal', 'BF%s.ex_', 'BD_Final')
indics <- purrr::compact(indics)
bd_finals <- purrr::compact(bd_finals)
São criadas duas listas: indics
e bd_finals
, com os datasets carregados dos arquivos da Bolsa utilizando os templates do rbmfbovespa.
Estas listas serão processadas para que sejam extraídos valores das taxas CDI e SELIC diárias e as taxas dos contratos futuros com vencimento mais recente, o primeiro vencimento.
Explico, hoje o contrato futuro com vencimento mais recente vence em 1 de fevereiro (ou no próximo dia útil), e este é o primeiro vencimento e este levantamento foi feito para cada data de referência.
O primeiro vencimento é importante porque ele traz a expectativa de movimento da CDI para o curto prazo (vencimento em menos de 1 mês) onde já é possível observar os movimentos provocados pela reunião do COPOM.
A função process_files
seleciona os contratos futuros de DI1 e as taxas SELIC e CDI para cada uma das datas levantadas.
process_files <- function(bdi, indic) {
# selecionar contratos futuros de DI1 dos arquivos BD_Final
futuro <- bdi %>% filter(cod_mercadoria == 'DI1') %>%
arrange(data_vencimento) %>%
filter(cot_ult_negocio != 0) %>%
filter(row_number() == 1) # selecionar o primeiro vencimento
# obter data de referência
ref_date <- bdi$data_geracao_arquivo[1]
# obter SELIC e CDI (DI1) dos arquivos Indic
cdi <- indic %>%
filter (cod_indicador == 'DI1', data_geracao_arquivo == ref_date)
selic <- indic %>%
filter (cod_indicador == 'SEL', data_geracao_arquivo == ref_date)
# data.frame com as informações necessárias
data.frame(data_referencia = cdi$data_geracao_arquivo,
data_vencimento = futuro$data_vencimento,
futuro = futuro$cot_ult_negocio,
cdi = cdi$valor_indicador,
selic = selic$valor_indicador)
}
ls_data <- purrr::map2(bd_finals, indics, process_files)
df <- do.call(rbind, ls_data)
Obtidos os dados no data.frame
df
podemos observar alguns fatos já mencionados, como a relação próxima entre SELIC e CDI.
No gráfico abaixo temos o histórico de SELIC e CDI desde 1 de dezembro de 2016.
Note que as taxas andam juntas e no dia seguinte a reunião do COPOM de 11 de janeiro de 2017 ambas as taxas mudaram de nível caindo 0.75%, exatamente resultado da reunião do COPOM do dia 11.
ggplot(df %>% select(-data_vencimento, -futuro) %>% gather(taxa, valor, -data_referencia),
aes(x = data_referencia, y = valor, colour = taxa, shape = taxa)) +
geom_vline(xintercept='2017-01-11' %>% as.Date() %>% as.integer(), linetype='dashed') +
scale_x_date() +
geom_point()
Outro ponto interessante de observar é a dinâmica do primeiro vencimento de futuro de DI1. O gráfico abaixo apresenta a dinâmica da taxa CDI com a taxa negociada no primeiro futuro.
ggplot(df %>% select(-data_vencimento, -selic) %>% gather(taxa, valor, -data_referencia),
aes(x = data_referencia, y = valor, colour = taxa, shape = taxa)) +
geom_vline(xintercept='2017-01-11' %>% as.Date() %>% as.integer(), linetype='dashed') +
geom_vline(xintercept=c('2017-01-01', '2017-02-01') %>% as.Date() %>% as.integer(), linetype='dotted') +
scale_x_date() +
geom_point()
Em dezembro de 2016 o primeiro vencimento vence no primeiro dia útil do ano, portanto a expectativa já está dada, não há fator que afete o nível da taxa CDI, por isso a CDI e a taxa do primeiro vencimento andam juntas. Após a virada do ano (primeira linha pontilhada), em janeiro de 2017, o primeiro futuro é o que vence em 1 de fevereiro. Note o descolamento entre a CDI e a taxa negociada no primeiro futuro, que indica uma redução na CDI para o vencimento de fevereiro. Entretanto, em 11 de janeiro ocorreu a primeira reunião do COPOM de 2017, que baixo a SELIC em 0.75% (linha tracejada). Após a reunião do COPOM o descolamento entre CDI e o primeiro vencimento desaparece novamente, pois para este período a taxa já está dada. O descolamento volta a aparecer em fevereiro quando o primeiro vencimento passa a expirar em março de 2017 e há uma reunião do COPOM em 22 de fevereiro de 2017.
Este descolamente entre a CDI e a taxa do primeiro futuro traz a expectativa do resultado da reunião do COPOM.
Vou mostrar como calcular essa expectativa.
Como é possível observar nos gráficos, a CDI e o primeiro futuro andam juntos quando o cenário está dado, e neste caso o cenário de taxa CDI está dado até a reunião do COPOM, ou seja, assumindo a hipótese de que a CDI não muda até a reunião do COPOM conclui-se que há espaço apenas para prever o nível da taxa após a reunião do COPOM.
A taxa do futuro é uma taxa média da data de referência até o seu vencimento.
Portanto, assumindo dada a taxa até a reunião do COPOM como a CDI da data de referência, é necessário calcular a taxa a termo da reunião do COPOM até o vencimento do futuro.
A função calc_taxa_termo
faz esse cálculo
calc_taxa_termo <- function(cdi, fut, duf, duc) {
f1 <- (1 + cdi/100)^(duc/252)
f2 <- (1 + fut/100)^(duf/252)
100*((f2/f1)^(252/(duf - duc)) - 1)
}
A fórmula fica assim:
$$ 100 \left[ \left( \frac{(1 + \frac{fut}{100})^{duf/252}}{(1 + \frac{cdi}{100})^{duc/252}} \right)^{\frac{252}{duf-duc}} - 1\right] $$
Essa é a taxa a termo que está implícita na taxa negociada no primeiro futuro que vence após a reunião do COPOM.
Pelo fato de a fórmula considerar os futuros com vencimento após a reunião do COPOM, é necessário remover todas as data onde o vencimento do futuro é anterior a próxima reunião do COPOM.
O código abaixo calcula os dias úteis necessários no cálculo e define as datas de reunião do COPOM, em seguida remove as datas e calcula a taxa à termo usando a função calc_taxa_termo
.
df_copom <- df %>%
mutate(
du=bizdays::bizdays(data_referencia, data_vencimento, 'Brazil/ANBIMA'),
data_copom=as.Date(ifelse(data_referencia <= as.Date('2017-01-11'), '2017-01-11', '2017-02-22'))
) %>%
filter(data_vencimento >= data_copom) %>%
mutate(
du_copom=bizdays::bizdays(data_referencia, data_copom, 'Brazil/ANBIMA'),
taxa_termo=calc_taxa_termo(cdi, futuro, du, du_copom)
)
O gráfico abaixo apresenta uma comparação das taxas CDI, do primeiro vencimento de futuro e da taxa à termo calculada. Observe que a taxa à termo e do futuro quase colapssam na data de reunão do COPOM (linha tracejada), o que é esperado uma vez que o prazo para a reunião está diminuindo. Para o mês de fevereiro temos um padrão semelhante.
ggplot(df_copom %>% select(data_referencia, cdi, futuro, taxa_termo) %>% gather(taxa, valor, -data_referencia),
aes(x = data_referencia, y = valor, colour = taxa, shape = taxa)) +
geom_vline(xintercept='2017-01-11' %>% as.Date() %>% as.integer(), linetype='dashed') +
geom_vline(xintercept=c('2017-01-01', '2017-02-01') %>% as.Date() %>% as.integer(), linetype='dotted') +
scale_x_date() +
geom_point()
A mudança na taxa apresentada na reunião do COPOM é a diferença entre a taxa a termo e a taxa CDI. Calculando esta diferença observamos que as expectativas estavam pouco acima de 0.50% de redução, e para a reunião de fevereiro temos expectativas em torno de 0.50%, houve até um dia que fechou em 0.60%. O gráfico abaixo apresenta esta diferença.
ggplot(data = df_copom, aes(x = data_referencia, y = taxa_termo - cdi)) +
geom_point(colour = 'red') +
geom_vline(xintercept='2017-01-11' %>% as.Date() %>% as.integer(), linetype='dashed') +
geom_hline(yintercept=-0.5)
Uma pergunta que fica após a observação destes resultados é, mesmo após a redução de 0.75% em janeiro, porque a expectativa está em 0.50%? Bem, os dados observados são referentes ao fechamento dos contratos futuros, obviamente ao longo do dia são negociados valores maiores e menores, que podem refletir movimentos de 0.75%, assim como 0.25%. Por exemplo, poderíamos repetir essa análise para as máximas e mínimas do dia.
Outro ponto interessante é a observação dos demais vencimentos, pois neles há a expectativa das demais reuniões. Por exemplo, após cada reunião do COPOM podemos migrar do primeiro para o segundo vencimento, pois a taxa do primeiro já está dada e toda a expectativa da próxima reunião está no segundo.