Create tarefa3
Browse files
tarefa3
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# ============================================================
|
| 2 |
+
# VAR-VECM • IRF • FEVD (Séries: PIB_real, Core PCE, Petróleo WTI)
|
| 3 |
+
# Requer: streamlit ≥ 1.25, pandas ≥ 2.0, statsmodels ≥ 0.14
|
| 4 |
+
# ============================================================
|
| 5 |
+
|
| 6 |
+
import streamlit as st
|
| 7 |
+
import pandas as pd
|
| 8 |
+
import numpy as np
|
| 9 |
+
import matplotlib.pyplot as plt
|
| 10 |
+
from pandas_datareader import data as web
|
| 11 |
+
from yahooquery import Ticker
|
| 12 |
+
from statsmodels.tsa.api import VAR
|
| 13 |
+
from statsmodels.tsa.vector_ar.vecm import VECM, coint_johansen
|
| 14 |
+
from statsmodels.tsa.stattools import adfuller
|
| 15 |
+
|
| 16 |
+
# ---------- CONFIGURAÇÃO DA PÁGINA ------------------------------------------
|
| 17 |
+
st.set_page_config(
|
| 18 |
+
page_title="Choques Macroeconômicos – VAR • VECM • IRF",
|
| 19 |
+
layout="wide",
|
| 20 |
+
initial_sidebar_state="expanded"
|
| 21 |
+
)
|
| 22 |
+
|
| 23 |
+
# ---------- FUNÇÃO PARA BAIXAR DADOS ----------------------------------------
|
| 24 |
+
@st.cache_data(show_spinner=False)
|
| 25 |
+
def fetch_series(start='2000-01-01', end=None):
|
| 26 |
+
"""
|
| 27 |
+
Baixa PIB real (trimestral), Core PCE (mensal) do FRED
|
| 28 |
+
e preço do petróleo WTI (diário) do YahooFinance;
|
| 29 |
+
devolve DataFrame log-nível, frequência mensal.
|
| 30 |
+
"""
|
| 31 |
+
end = end or pd.Timestamp.today().strftime("%Y-%m-%d")
|
| 32 |
+
|
| 33 |
+
# --- FRED ---------------------------------------------------------------
|
| 34 |
+
fred = web.DataReader(['GDPC1', 'PCEPILFE'], 'fred', start, end)
|
| 35 |
+
pib_log = np.log(fred['GDPC1']).to_period('M').to_timestamp('M')
|
| 36 |
+
pce_log = np.log(fred['PCEPILFE']).resample('M').last()
|
| 37 |
+
|
| 38 |
+
# --- WTI ---------------------------------------------------------------
|
| 39 |
+
wti_raw = Ticker('CL=F').history(start=start, end=end)['adjclose'].droplevel(0)
|
| 40 |
+
wti_log = np.log(wti_raw).resample('M').last()
|
| 41 |
+
|
| 42 |
+
df = (
|
| 43 |
+
pd.concat([pib_log, pce_log, wti_log], axis=1)
|
| 44 |
+
.dropna()
|
| 45 |
+
.rename(columns={
|
| 46 |
+
'GDPC1' : 'PIB_log',
|
| 47 |
+
'PCEPILFE': 'CORE_PCE_log',
|
| 48 |
+
'adjclose': 'WTI_log'
|
| 49 |
+
})
|
| 50 |
+
)
|
| 51 |
+
return df
|
| 52 |
+
|
| 53 |
+
# ---------- SIDEBAR ---------------------------------------------------------
|
| 54 |
+
st.sidebar.title("Controles do modelo")
|
| 55 |
+
|
| 56 |
+
start_date = st.sidebar.date_input("Data inicial", pd.to_datetime("2000-01-01"))
|
| 57 |
+
lags = st.sidebar.slider("Número de lags (p)", 1, 12, 6)
|
| 58 |
+
conf = st.sidebar.slider("Nível de confiança (%)", 80, 99, 95)
|
| 59 |
+
model_type = st.sidebar.selectbox("Modelo", ["VECM", "VAR"])
|
| 60 |
+
show_fe = st.sidebar.checkbox("Exibir FEVD", value=False)
|
| 61 |
+
h_irf = st.sidebar.slider("Horizonte IRF (meses)", 1, 36, 12)
|
| 62 |
+
|
| 63 |
+
# ---------- CARREGAR DADOS --------------------------------------------------
|
| 64 |
+
with st.spinner("Baixando séries…"):
|
| 65 |
+
df = fetch_series(start=start_date.strftime("%Y-%m-%d"))
|
| 66 |
+
|
| 67 |
+
st.markdown("### Séries em log-nível (mensal)")
|
| 68 |
+
st.line_chart(df)
|
| 69 |
+
|
| 70 |
+
# ---------- TESTES ADF / JOHANSEN ------------------------------------------
|
| 71 |
+
with st.expander("Testes de estacionariedade e cointegração", expanded=False):
|
| 72 |
+
col_test = st.columns(2)
|
| 73 |
+
|
| 74 |
+
with col_test[0]:
|
| 75 |
+
st.subheader("ADF (nível)")
|
| 76 |
+
for col in df.columns:
|
| 77 |
+
stat, p, *_ = adfuller(df[col])
|
| 78 |
+
st.write(f"**{col}** ADF={stat:.2f} p={p:.4f}")
|
| 79 |
+
|
| 80 |
+
with col_test[1]:
|
| 81 |
+
joh = coint_johansen(df, det_order=0, k_ar_diff=lags)
|
| 82 |
+
st.subheader("Johansen – Trace")
|
| 83 |
+
for i, (ts, cv) in enumerate(zip(joh.lr1, joh.cvt[:,1])):
|
| 84 |
+
decision = "Rejeita" if ts > cv else "Não rejeita"
|
| 85 |
+
st.write(f"r≤{i}: trace {ts:.2f} > crit5 {cv:.2f}? **{decision}**")
|
| 86 |
+
|
| 87 |
+
# ---------- AJUSTE DO MODELO -----------------------------------------------
|
| 88 |
+
if model_type == "VAR":
|
| 89 |
+
var = VAR(df).fit(lags)
|
| 90 |
+
st.success(f"VAR({lags}) ajustado.")
|
| 91 |
+
else:
|
| 92 |
+
r = sum(joh.lr1 > joh.cvt[:,1]) # rank pelo trace
|
| 93 |
+
vecm = VECM(df, k_ar_diff=lags, coint_rank=r, deterministic='co').fit()
|
| 94 |
+
st.success(f"VECM ajustado: rank={r}, p={lags}")
|
| 95 |
+
|
| 96 |
+
# ---------- IRF -------------------------------------------------------------
|
| 97 |
+
with st.expander(" Impulse Response Function (IRF)", expanded=True):
|
| 98 |
+
impulse = st.selectbox("Choque (impulse)", df.columns, index=2)
|
| 99 |
+
response = st.selectbox("Resposta", df.columns, index=0)
|
| 100 |
+
ic = 1 - conf/100
|
| 101 |
+
|
| 102 |
+
if model_type == "VAR":
|
| 103 |
+
irf = var.irf(h_irf).plot(impulse=impulse, response=response,
|
| 104 |
+
orth=False, signif=ic)
|
| 105 |
+
else:
|
| 106 |
+
irf = vecm.irf(h_irf).plot(impulse=impulse, response=response,
|
| 107 |
+
orth=False, signif=ic)
|
| 108 |
+
|
| 109 |
+
st.pyplot(irf.figure)
|
| 110 |
+
|
| 111 |
+
# ---------- FEVD ------------------------------------------------------------
|
| 112 |
+
if show_fe:
|
| 113 |
+
st.markdown("### Forecast-Error Variance Decomposition")
|
| 114 |
+
if model_type == "VAR": # FEVD só p/ VAR em statsmodels 0.13
|
| 115 |
+
fevd = var.fevd(h_irf)
|
| 116 |
+
else:
|
| 117 |
+
fevd = vecm.fevd(h_irf)
|
| 118 |
+
|
| 119 |
+
horizons = [1, 6, 12, h_irf]
|
| 120 |
+
tbl = pd.concat(
|
| 121 |
+
{h: pd.DataFrame(fevd.decomp[h],
|
| 122 |
+
columns=[f"Shock_{v}" for v in df.columns],
|
| 123 |
+
index=[f"Var_{v}" for v in df.columns])
|
| 124 |
+
for h in horizons},
|
| 125 |
+
axis=0
|
| 126 |
+
).round(3)*100
|
| 127 |
+
st.dataframe(tbl)
|
| 128 |
+
|
| 129 |
+
# ---------- Rodapé ----------------------------------------------------------
|
| 130 |
+
st.caption("Dados: FRED (GDP, Core PCE) & Yahoo Finance (WTI). "
|
| 131 |
+
"Aplicação didática para Engenharia de Produtos Financeiros (UnB-FACE).")
|