Medindo o efeito da volatilidade sobre a taxa de câmbio

Nesse exercício, verificamos a relação entre o índice de volatilidade (VIX) e a taxa de câmbio. A ideia básica, é a de que, a volatilidade, e portanto, a incerteza do mercado gera mudanças significativas sobre o preço do câmbio. Fazemos o uso do procedimento de Toda-Yamamoto para investigar essa relação usando o Python como ferramenta.

De forma a analisar essa suposição, devemos investigar através de uma análise de dados, os possíveis acontecimentos que ocasionaram mudanças em variáveis que descrevem a dinâmica de precedência temporal.

Feito a análise de dados, podemos prosseguir para verificar se, de fato, existe influência do índice de volatilidade no comportamento da taxa de câmbio. Para isso, vamos executar o procedimento de Toda-Yamamoto.

1. Carregamento de bibliotecas


import pandas as pd
import pandas_datareader.data as web
import datetime
from plotnine import *
from bcb import sgs
import statsmodels.api as sm # modelagem
from statsmodels.tsa.api import VAR # Vetores Autoregressivos
from statsmodels.tsa.stattools import adfuller

 

2. Análise de Dados

2.1 Juro de 10 anos dos Estados Unidos

No últimos anos, vimos uma intensa mudança de preços nos mercados internacionais em resposta, principalmente, de choques de oferta, proporcionados pela pandemia e Invasão da Ucrânia pela Rússia.

Eventos subsequentes seguirão com as respostas dos Bancos Centrais para apaziguar a escalada das taxas de inflação, gerando a preocupação, se, no futuro haverá ou não um “soft landing”.

O juro de 10 anos dos Estados Unidos abriu o ano de 2022 com uma tendência positiva, dando sinais de que romperia a barreira “psicológica” de 3% a.a.. Além de ocorrer, houve a persistência da taxa no valor acima de 4% a.a. em 2023, devido às preocupações com a economia norte-americana e chinesa.

Vemos abaixo como analisar o gráfico do Juro de 10 anos do EUA usando o Python.

# Define as datas de início e fim
start = datetime.datetime(2018, 1, 1)
end = datetime.datetime(2023, 9, 1)

# Captura os dados
treasuries = web.DataReader(['DGS10'], 'fred', start, end).dropna().reset_index()

treasuries

 

DATE DGS10
0 2018-01-02 2.46
1 2018-01-03 2.44
2 2018-01-04 2.46
3 2018-01-05 2.47
4 2018-01-08 2.49
... ... ...
1414 2023-08-28 4.20
1415 2023-08-29 4.12
1416 2023-08-30 4.12
1417 2023-08-31 4.09
1418 2023-09-01 4.18

1419 rows × 2 columns

(ggplot(treasuries)
+ aes(x = 'DATE', y = 'DGS10')
+ geom_line(size = .8, color = "darkblue")
+ geom_hline(yintercept = 3, colour = 'red', linetype = "dashed")
+ scale_x_date(date_breaks = '1 years', date_labels = '%b/%Y')
+ theme(axis_text_x = element_text(angle = 45, hjust = 1))
+ labs(title = "Juro de 10 anos dos EUA",
caption = "Elaborado por analisemacro.com.br | Fonte: FRED",
y = "% a.a",
x = "")
+ theme_minimal()
)

2.2 Índice de Volatilidade (VIX−CBOE)

Simultaneamente a elevação do Juro de 10 anos no EUA em 2018, vimos a ocorrência da elevação no índice de volatilidade VIX do CBOE. Ao passo que até anteriormente à pandemia de COVID, tivemos uma tendência de baixa de ambas as variáveis, período no qual o VIX encontrava-se abaixo de sua média histórica.

Entretanto, a partir da pandemia, com a elevação do VIX, o Juro de 10 anos teve um movimento contrário, devido as adversidades proporcionadas pelos choques.

E que apesar de queda significativa do VIX de 2022 até 2023, vimos um movimento contrário altista nos Juros de 10 anos.

# Captura os dados
vix = web.DataReader(['VIXCLS'], 'fred', start, end).dropna().reset_index()

vix
DATE VIXCLS
0 2018-01-02 9.77
1 2018-01-03 9.15
2 2018-01-04 9.22
3 2018-01-05 9.22
4 2018-01-08 9.52
... ... ...
1432 2023-08-28 15.08
1433 2023-08-29 14.45
1434 2023-08-30 13.88
1435 2023-08-31 13.57
1436 2023-09-01 13.09

1437 rows × 2 columns

(ggplot(vix)
+ aes(x = 'DATE', y = 'VIXCLS')
+ geom_line(size = .8, colour = "darkblue")
+ geom_hline(yintercept = vix.VIXCLS.mean(), colour = 'red', linetype = "dashed")
+ scale_x_date(date_breaks = '1 years', date_labels = '%b/%Y')
+ theme(axis_text_x = element_text(angle = 45, hjust = 1))
+ labs(title = "Índice de Volatilidade (VIX−CBOE)",
caption = "Elaborado por analisemacro.com.br | Fonte: FRED",
y = "",
x = "")
+ theme_minimal()
)


2.3 Taxa de câmbio - Livre - Dólar americano (venda) - diário

Os efeitos no VIX e taxas de Juros no EUA ocorridos durante a pandemia de COVID também podem ser verificados na taxa de câmbio, com ampla desvalorização da moeda brasileira.

Ao passo que em 2023, havia uma tendência de queda, concomitante a queda do VIX, a tendência altista dos Juros de 10 anos não permitiu essa desvalorização acentuada.

cambio = sgs.get({'cambio' : 1}, start = start, end = end).reset_index()
cambio

 

Date cambio
0 2017-12-29 3.3080
1 2018-01-02 3.2697
2 2018-01-03 3.2535
3 2018-01-04 3.2318
4 2018-01-05 3.2409
... ... ...
1421 2023-08-28 4.8938
1422 2023-08-29 4.8706
1423 2023-08-30 4.8653
1424 2023-08-31 4.9219
1425 2023-09-01 4.9318

1426 rows × 2 columns

(ggplot(cambio)
+ aes(x = 'Date', y = 'cambio')
+ geom_line(size = .8, colour = "darkblue")
+ scale_x_date(date_breaks = '1 years', date_labels = '%b/%Y')
+ theme(axis_text_x = element_text(angle = 45, hjust = 1))
+ labs(title = "Taxa de câmbio - Livre - Dólar americano (venda) - diário",
caption = "Elaborado por analisemacro.com.br | Fonte: BCB",
y = "R$",
x = "")
+ theme_minimal()
)

3. Procedimento de Toda-Yamamoto

O procedimento Toda-Yamamoto é baseado no conceito de causalidade de Granger, que postula que uma variável X “causa” (no sentido granger) outra variável Y se as informações passadas de X ajudarem a prever melhor Y do que apenas as informações passadas de Y. O teste de Toda-Yamamoto é uma extensão do teste de causalidade de Granger, que leva em consideração a presença de tendências e estruturas não lineares nas séries temporais.

Em caso de não estacionariedade de uma ou mais séries envolvidas no Teste de Granger, é possível que os resultados encontrados sejam espúrios. Nesses casos, um procedimento mais abrangente para ver a relação entre variáveis foi estabelecido na literatura por Toda e Yamamoto (1995). Para ilustrar o procedimento, vamos considerar as séries da Taxa de juros de 10 anos do EUA, o índice de volatilidade (VIX) e Taxa de câmbio - Livre - Dólar americano (venda) - diário.

O procedimento descrito por Toda e Yamamoto (1995) consiste, basicamente, nos seguintes passos:

  1. Verificar a ordem de integração das variáveis através de testes de raiz unitária e estacionariedade;
  2. Definir a ordem máxima (m) de integração entre as variáveis;
  3. Montar o VAR em nível para as variáveis;
  4. Determinar a ordem de defasagem do VAR(p) pelos critérios de informação tradicionais;
  5. Ver a estabilidade do modelo, em particular problemas de autocorrelação;
  6. Se estiver tudo certo, adicionar m defasagens ao VAR, de modo que você terá um VAR(p+m);
  7. Rodar o teste de Wald com p coeficientes e p graus de liberdade.

3.1. Tratamento dos dados

Antes de prosseguir com a montagem do VAR, devemos realizar alguns tratamentos em nossas variáveis.

Renomeamos a coluna de data, de forma que possamos unir os data frames pela mesma coluna (Date).

</pre>
# Renomeia as colunas
vix.rename(columns = {'DATE' : 'Date'}, inplace = True)
treasuries.rename(columns = {'DATE' : 'Date'}, inplace = True)

# Junta os dados
dados = vix.merge(cambio, on = 'Date')
dados = dados.merge(treasuries, on = 'Date').set_index('Date')
<pre>

 

3.2 Aplicação do Procedimento

Uma vez criado o Data Frame, devemos prosseguir com os passos elencados anteriormente.

1) Verificar a ordem de integração das variáveis através de testes de raiz unitária e estacionariedade.

O código e o resultado abaixo entrega o teste ADF de forma prática.

def adfuller_test(dataframe, signif=0.05, verbose=False):
"""Realiza o teste ADFuller para verificar a estacionaridade das colunas de um DataFrame e imprime o relatório"""
for coluna in dataframe.columns:
series = dataframe[coluna]
r = adfuller(series, autolag='AIC')
output = {'estatística_do_teste': round(r[0], 4), 'valor_p': round(r[1], 4), 'número_de_lags': round(r[2], 4), 'número_de_observações': r[3]}
valor_p = output['valor_p']

def ajustar(valor, comprimento=6):
return str(valor).ljust(comprimento)

# Imprimir resumo
print(f'Teste de Dickey-Fuller Aumentado em "{coluna}"', "\n", '-' * 47)
print(f'Hipótese Nula: Os dados possuem raiz unitária. Não estacionários.')
print(f'Nível de Significância = {signif}')
print(f'Estatística do Teste = {output["estatística_do_teste"]}')
print(f'Número de Lags Escolhidos = {output["número_de_lags"]}')

for chave, valor in r[4].items():
print(f'Valor Crítico {ajustar(chave)} = {round(valor, 3)}')

if valor_p <= signif:
print(f" => Valor-P = {valor_p}. Rejeitando a Hipótese Nula.")
print(f" => A série é Estacionária.")
else:
print(f" => Valor-P = {valor_p}. Evidência fraca para rejeitar a Hipótese Nula.")
print(f" => A série não é Estacionária.")
print("\n")

# Realiza o teste para as séries do df
adfuller_test(dados)
<pre>

 

Código
Teste de Dickey-Fuller Aumentado em "VIXCLS" 
 -----------------------------------------------
Hipótese Nula: Os dados possuem raiz unitária. Não estacionários.
Nível de Significância = 0.05
Estatística do Teste    = -4.5299
Número de Lags Escolhidos = 9
Valor Crítico 1%     = -3.435
Valor Crítico 5%     = -2.864
Valor Crítico 10%    = -2.568
 => Valor-P = 0.0002. Rejeitando a Hipótese Nula.
 => A série é Estacionária.


Teste de Dickey-Fuller Aumentado em "cambio" 
 -----------------------------------------------
Hipótese Nula: Os dados possuem raiz unitária. Não estacionários.
Nível de Significância = 0.05
Estatística do Teste    = -2.0463
Número de Lags Escolhidos = 1
Valor Crítico 1%     = -3.435
Valor Crítico 5%     = -2.864
Valor Crítico 10%    = -2.568
 => Valor-P = 0.2667. Evidência fraca para rejeitar a Hipótese Nula.
 => A série não é Estacionária.


Teste de Dickey-Fuller Aumentado em "DGS10" 
 -----------------------------------------------
Hipótese Nula: Os dados possuem raiz unitária. Não estacionários.
Nível de Significância = 0.05
Estatística do Teste    = -0.1662
Número de Lags Escolhidos = 0
Valor Crítico 1%     = -3.435
Valor Crítico 5%     = -2.864
Valor Crítico 10%    = -2.568
 => Valor-P = 0.9424. Evidência fraca para rejeitar a Hipótese Nula.
 => A série não é Estacionária.

2) Definir a ordem máxima (m) de integração entre as variáveis.

Como verificado anteriormente, ambas as séries não são estacionárias de acordo com o teste ADF. De forma a simplificar o processos, vamos definir que, como boa parte das séries econômicas, as séries sejam estacionarias a partir de uma simples diferenciação, e portanto, que sejam I(1).

3) Montar o VAR em nível para as variáveis.

# Instância a classe VAR com os dados
var = VAR(dados)

 

4) Determinar a ordem de defasagem do VAR(p) pelos critérios de informação tradicionais

Por meio do método select_order, verificamos que a partir de diferentes critérios de seleção para os dados utilizados, temos p = 2.

A partir disso, ajustamos um VAR(2).

# Verificar a ordem de defasagem do VAR por critérios de seleção
order = var.select_order(maxlags = 6, trend = "ct")

# Verifica as ordens de acordo com critérios de seleção
order.selected_orders

 

Código
{'aic': 4, 'bic': 2, 'hqic': 2, 'fpe': 4}
# Realiza o ajuste do VAR(2) com constante e tendência
var_result = var.fit(maxlags = 2, trend = 'ct')

 

5) Ver a estabilidade do modelo, em particular problemas de autocorrelação

O Portmanteau Test é usado para avaliar se existe autocorrelação residual significativa em um modelo ajustado, ou seja, se há dependência linear entre os resíduos em diferentes defasagens.

Se os resíduos são verdadeiramente aleatórios, espera-se que as autocorrelações sejam próximas de zero. O teste calcula uma estatística de teste baseada nas autocorrelações dos resíduos em várias defasagens e a compara com uma distribuição qui-quadrado para determinar se há autocorrelação significativa.

Queremos achar um modelo tal que não rejeite a hipótese nula de ausência de autocorrelação, isto é, não desejamos obter um resultado do p-value do Portmanteau Test menor de 0,05 (5%).

Rejeitamos a hipótese nula, entretanto, confirmamos a estabilidade do modelo. De forma a finalizar o exercício, ignoraremos esse problema e aplicamos o restante dos processos.

# Realiza o teste de correlação serial dos erros
var_auto = var_result.test_whiteness()

print(var_auto.summary())

 
Código
Portmanteau-test for residual autocorrelation. H_0: residual autocorrelation up to lag 10 is zero. Conclusion: reject H_0 at 5% significance level.
========================================
Test statistic Critical value p-value df
----------------------------------------
         129.2          92.81   0.000 72
----------------------------------------
var_result.is_stable()

True

6) Adicionar m defasagens ao VAR, de modo que você terá um VAR(p+m);

 
# Realiza o ajuste do VAR(3) com constante e tendência
var_result_m = var.fit(maxlags = 3, trend = 'ct')

7) Rodar o teste de Wald com p coeficientes e p graus de liberdade.

Agora vamos verificar a causalidade.

Para tanto, utilizamos o Wald test, que é um teste estatístico utilizado para avaliar a significância dos coeficientes estimados em modelos de regressão. Ele é baseado na comparação entre a estimativa do coeficiente e a sua variância estimada.

Para tanto vamos testar a hipótese nula de que um coeficiente é igual a zero. A ideia é verificar se a estimativa do coeficiente é estatisticamente diferente de zero, o que indicaria a presença de um efeito significativo da variável explicativa correspondente sobre a variável resposta.

Se a estatística de teste calculada for maior do que o valor crítico da distribuição qui-quadrado, rejeita-se a hipótese nula, indicando que o coeficiente é significativamente diferente de zero.

Por outro lado, se a estatística de teste for menor do que o valor crítico, não há evidência suficiente para rejeitar a hipótese nula, sugerindo que o coeficiente não é significativamente diferente de zero.

# Realiza o teste de causalidade de Toda-Yamamoto
causality_test1 = var_result_m.test_causality(caused = 'VIXCLS', causing = ['cambio'], kind = 'wald')

print(causality_test1.summary())
Código
Granger causality Wald-test. H_0: cambio does not Granger-cause VIXCLS. Conclusion: fail to reject H_0 at 5% significance level.
========================================
Test statistic Critical value p-value df
----------------------------------------
         7.629          7.815   0.054  3
----------------------------------------
</pre>
# Realiza o teste de causalidade de Toda-Yamamoto
causality_test2 = var_result_m.test_causality(caused = 'cambio', causing = ['VIXCLS'], kind = 'wald')

print(causality_test2.summary())
<pre>
Código
Granger causality Wald-test. H_0: VIXCLS does not Granger-cause cambio. Conclusion: reject H_0 at 5% significance level.
========================================
Test statistic Critical value p-value df
----------------------------------------
         16.05          7.815   0.001  3
----------------------------------------

Considerações

Considerado o exercício, podemos dizer que o VIX granger causa Câmbio. Ou seja, há precedência temporal do índice sobre o câmbio brasileiro.

Quer aprender mais?

 -  Cadastre-se gratuitamente aqui no Boletim AM e receba toda terça-feira pela manhã nossa newsletter com um compilado dos nossos exercícios com exemplos reais de análise de dados envolvendo as áreas de Data Science, Econometria, Machine Learning, Macroeconomia Aplicada, Finanças Quantitativas e Políticas Públicas;

 - Quer ter acesso aos códigos, vídeos e scripts de R/Python desse exercício? Vire membro do Clube AM aqui e tenha acesso à nossa Comunidade de Análise de Dados;

 - Quer aprender a programar em R ou Python com Cursos Aplicados e diretos ao ponto em Data Science, Econometria, Machine Learning, Macroeconomia Aplicada, Finanças Quantitativas e Políticas Públicas? Veja nossos Cursos aqui.

Compartilhe esse artigo

Facebook
Twitter
LinkedIn
WhatsApp
Telegram
Email
Print

Comente o que achou desse artigo

Outros artigos relacionados

Análise regional do mercado de trabalho com dados do CAGED usando Python

Os microdados dos CAGED fornecem informações detalhadas a nível de cidade, sexo, raça, nível de instrução, idade, salário e outras sobre os trabalhadores formais do Brasil, possibilitando ricas análises regionais de dados. Neste artigo mostramos como acessar, processar e analisar estes dados utilizando o Python.

Transfer Learning: mostrando porque o Python está na ponta do desenvolvimento

A aprendizagem por transferência (transfer learning) é o reuso de um modelo pré-treinado em um novo problema. Portanto, sua utilização torna-se um avanço enorme para a previsão de diferentes tipos de variáveis, principalmente para aquelas ordenadas no tempo. Mostramos nesta postagem o uso do Transfer Learning com o Python para o caso de Séries Temporais.

como podemos ajudar?

Preencha os seus dados abaixo e fale conosco no WhatsApp

Boletim AM

Preencha o formulário abaixo para receber nossos boletins semanais diretamente em seu e-mail.