# ====================================================== # 📉 Choques Macros • VAR · VECM · IRF · FEVD (FRED-only) # ====================================================== import streamlit as st import pandas as pd, numpy as np, matplotlib.pyplot as plt from pandas_datareader import data as web from statsmodels.tsa.api import VAR from statsmodels.tsa.vector_ar.vecm import VECM, coint_johansen from statsmodels.tsa.stattools import adfuller # ---------- Página ---------- st.set_page_config("Choques Macros – VAR/VECM", layout="wide") # ---------- Função de dados ---------- @st.cache_data(ttl=3600, show_spinner=False) def load_data(start="2000-01-01", end=None): end = end or pd.Timestamp.today().strftime("%Y-%m-%d") fred = web.DataReader(["GDPC1", "PCEPILFE", "DCOILWTICO"], "fred", start, end) df = pd.concat( [ np.log(fred["GDPC1"]).to_period("M").to_timestamp("M"), np.log(fred["PCEPILFE"]).resample("M").last(), np.log(fred["DCOILWTICO"]).resample("M").last(), ], axis=1, ).dropna() df.columns = ["PIB_log", "CORE_PCE_log", "WTI_log"] return df # ---------- Sidebar ---------- st.sidebar.title("🎛️ Controles") ini = st.sidebar.date_input("Data inicial", pd.to_datetime("2000-01-01")) lags = st.sidebar.slider("Lags (p)", 1, 12, 6) conf = st.sidebar.slider("Confiança (%)", 80, 99, 95) modelo = st.sidebar.selectbox("Modelo", ["VECM", "VAR"]) show_fevd = st.sidebar.checkbox("FEVD") h_irf = st.sidebar.slider("Horizonte IRF (m)", 1, 36, 12) # ---------- Dados ---------- with st.spinner("🔄 Baixando FRED…"): df = load_data(ini.strftime("%Y-%m-%d")) st.line_chart(df) # ---------- Testes ---------- with st.expander("🧪 Testes"): col1, col2 = st.columns(2) with col1: st.subheader("ADF") for c in df: stat, p, *_ = adfuller(df[c]) st.write(f"{c}: ADF={stat:.2f}, p={p:.4f}") with col2: joh = coint_johansen(df, 0, lags) st.subheader("Johansen") for i, (ts, cv) in enumerate(zip(joh.lr1, joh.cvt[:, 1])): st.write(f"r≤{i}: {ts:.2f} / {cv:.2f}") # ---------- Ajuste ---------- if modelo == "VAR": res = VAR(df).fit(lags) st.success(f"VAR({lags}) ajustado") else: rank = sum(joh.lr1 > joh.cvt[:, 1]) res = VECM(df, k_ar_diff=lags, coint_rank=rank, deterministic="co").fit() st.success(f"VECM ajustado (rank={rank})") # ---------- IRF ---------- with st.expander("🚀 IRF", expanded=True): imp = st.selectbox("Impulso", df.columns, 2) resp = st.selectbox("Resposta", df.columns, 0) alpha = 1 - conf / 100 fig = res.irf(h_irf).plot(impulse=imp, response=resp, orth=False, signif=alpha) st.pyplot(fig.figure) # ---------- FEVD ---------- if show_fevd: st.subheader("📈 FEVD") fevd = res.fevd(h_irf) for h in [1, 6, 12]: if h <= h_irf: st.write(f"**h={h}**") tbl = pd.DataFrame( fevd.decomp[h], columns=[f"Shock_{c}" for c in df.columns], index=df.columns, ).round(2) * 100 st.dataframe(tbl) st.caption("Dados: FRED (GDPC1, PCEPILFE, DCOILWTICO) • Demo UnB EPF")