joaogabrielsouza commited on
Commit
76ff267
·
0 Parent(s):

Publicação inicial do dashboard de diagnóstico de séries temporais

Browse files
Dashboard_Diagnostico_ST.py ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ # coding: utf-8
3
+
4
+ import streamlit as st
5
+ import pandas as pd
6
+ import numpy as np
7
+ from yahooquery import Ticker
8
+ import plotly.graph_objects as go
9
+ from statsmodels.tsa.stattools import adfuller, kpss, acf, pacf
10
+ from statsmodels.stats.diagnostic import acorr_ljungbox, het_arch
11
+ from statsmodels.stats.stattools import jarque_bera
12
+ from PIL import Image
13
+
14
+ # Configuração da página
15
+ st.set_page_config(
16
+ page_title="Diagnóstico de Séries Temporais Financeiras",
17
+ layout="wide",
18
+ initial_sidebar_state="expanded"
19
+ )
20
+
21
+ # Estilo do slider
22
+ st.markdown("""
23
+ <style>
24
+ .stSlider > div > div > div > div > div > div {
25
+ background-color: #4CAF50 !important;
26
+ }
27
+ </style>
28
+ """, unsafe_allow_html=True)
29
+
30
+ # Logo
31
+ logo_unb = Image.open("Logo/MARCADOR.png")
32
+ col1, col2, col3 = st.columns([1, 6, 1])
33
+ with col1:
34
+ st.image(logo_unb, use_column_width=True)
35
+ with col2:
36
+ st.markdown("<h1 style='text-align: center; color: #003366;'>Diagnóstico de Séries Temporais Financeiras</h1>", unsafe_allow_html=True)
37
+ st.markdown("<h3 style='text-align: center; color: #003366;'>Professor João Gabriel de Moraes Souza</h3>", unsafe_allow_html=True)
38
+ with col3:
39
+ st.image(logo_unb, use_column_width=True)
40
+
41
+ # Interface
42
+ ativos = ['ITUB4.SA', 'BBAS3.SA', 'BBDC4.SA', 'PETR3.SA', 'CSNA3.SA']
43
+ ativo = st.selectbox("Escolha um ativo:", ativos)
44
+ tipo_serie = st.radio("Tipo de série:", ["Preços", "Retornos"])
45
+ alpha = st.slider("Nível de significância (α):", min_value=0.01, max_value=0.10, value=0.01, step=0.01)
46
+ diagnostico = st.selectbox("Escolha o tipo de diagnóstico:", [
47
+ "Estacionariedade",
48
+ "Ergodicidade",
49
+ "Autocorrelação",
50
+ "Heterocedasticidade",
51
+ "Normalidade"
52
+ ])
53
+
54
+ # Cache para download de dados
55
+ @st.cache_data(ttl=3600)
56
+ def carregar_dados(ativo):
57
+ ticker = Ticker(ativo)
58
+ df_raw = ticker.history(start='2012-01-01', interval='1d').reset_index()
59
+ df_raw['date'] = pd.to_datetime(df_raw['date'], utc=True, errors='coerce').dt.tz_convert(None)
60
+ df_prices = df_raw[df_raw['adjclose'].notna()][['date', 'adjclose']].rename(columns={'date': 'Data', 'adjclose': 'Preco'})
61
+ df_prices.set_index('Data', inplace=True)
62
+ df_prices = df_prices[~df_prices.index.duplicated()]
63
+ return df_prices
64
+
65
+ # Carregar dados cacheados
66
+ df_prices = carregar_dados(ativo)
67
+
68
+ # Calcular série conforme tipo
69
+ if tipo_serie == "Retornos":
70
+ serie = np.log(df_prices / df_prices.shift(1)).dropna()
71
+ else:
72
+ serie = df_prices.copy()
73
+
74
+ # Visualização da série
75
+ st.markdown("### Dados Históricos")
76
+ st.line_chart(serie)
77
+
78
+ # Diagnóstico
79
+ st.markdown(f"### Diagnóstico: {diagnostico}")
80
+
81
+ if diagnostico == "Estacionariedade":
82
+ try:
83
+ adf_stat, adf_p, *_ = adfuller(serie.values.flatten())
84
+ if adf_p < alpha:
85
+ st.success(f"ADF: p-valor = {adf_p:.4f} < α → estacionária ao nível de {alpha*100:.0f}%")
86
+ else:
87
+ st.warning(f"ADF: p-valor = {adf_p:.4f} ≥ α → não estacionária ao nível de {alpha*100:.0f}%")
88
+ except Exception as e:
89
+ st.error(f"Erro no teste ADF: {e}")
90
+
91
+ try:
92
+ kpss_stat, kpss_p, *_ = kpss(serie.values.flatten(), nlags='auto')
93
+ if kpss_p < alpha:
94
+ st.warning(f"KPSS: p-valor = {kpss_p:.4f} < α → rejeita estacionariedade ao nível de {alpha*100:.0f}%")
95
+ else:
96
+ st.success(f"KPSS: p-valor = {kpss_p:.4f} ≥ α → estacionariedade não rejeitada")
97
+ except Exception as e:
98
+ st.error(f"Erro no teste KPSS: {e}")
99
+
100
+ elif diagnostico == "Ergodicidade":
101
+ expanding_mean = serie.expanding().mean()
102
+ fig = go.Figure([go.Scatter(x=expanding_mean.index, y=expanding_mean.values.flatten())])
103
+ fig.update_layout(title="Média Acumulada (Ergodicidade)", xaxis_title="Data", yaxis_title="Média")
104
+ st.plotly_chart(fig)
105
+
106
+ elif diagnostico == "Autocorrelação":
107
+ try:
108
+ serie_valida = serie.values.flatten()
109
+ serie_valida = serie_valida[~np.isnan(serie_valida)]
110
+ serie_valida = serie_valida[~np.isinf(serie_valida)]
111
+
112
+ if len(serie_valida) > 30 and np.std(serie_valida) > 0:
113
+ lb_p = acorr_ljungbox(serie_valida, lags=[10], return_df=True)['lb_pvalue'].iloc[0]
114
+ if lb_p < alpha:
115
+ st.warning(f"Ljung-Box: p-valor = {lb_p:.4f} < α → autocorrelação presente")
116
+ else:
117
+ st.success(f"Ljung-Box: p-valor = {lb_p:.4f} ≥ α → sem evidência de autocorrelação")
118
+ else:
119
+ st.warning("Série inválida para o teste de Ljung-Box: tamanho insuficiente ou variância nula.")
120
+ except Exception as e:
121
+ st.error(f"Erro no teste Ljung-Box: {e}")
122
+
123
+ try:
124
+ acf_vals = acf(serie_valida, nlags=30)
125
+ pacf_vals = pacf(serie_valida, nlags=30)
126
+ lags = list(range(len(acf_vals)))
127
+
128
+ fig_acf = go.Figure([go.Bar(x=lags, y=acf_vals)])
129
+ fig_acf.update_layout(title="Autocorrelação (ACF)", xaxis_title="Lag", yaxis_title="ACF")
130
+ st.plotly_chart(fig_acf)
131
+
132
+ fig_pacf = go.Figure([go.Bar(x=lags, y=pacf_vals)])
133
+ fig_pacf.update_layout(title="Autocorrelação Parcial (PACF)", xaxis_title="Lag", yaxis_title="PACF")
134
+ st.plotly_chart(fig_pacf)
135
+
136
+ except Exception as e:
137
+ st.error(f"Erro nos gráficos ACF/PACF: {e}")
138
+
139
+ elif diagnostico == "Heterocedasticidade":
140
+ try:
141
+ serie_valida = serie.values.flatten()
142
+ serie_valida = serie_valida[~np.isnan(serie_valida)]
143
+ serie_valida = serie_valida[~np.isinf(serie_valida)]
144
+
145
+ if len(serie_valida) > 30 and np.std(serie_valida) > 0:
146
+ p_arch = het_arch(serie_valida)[1]
147
+ if p_arch < alpha:
148
+ st.warning(f"ARCH: p-valor = {p_arch:.4f} < α → heterocedasticidade condicional presente")
149
+ else:
150
+ st.success(f"ARCH: p-valor = {p_arch:.4f} ≥ α → sem evidência de heterocedasticidade")
151
+ else:
152
+ st.warning("Série inválida para o teste ARCH: tamanho insuficiente ou variância nula.")
153
+ except Exception as e:
154
+ st.error(f"Erro no teste ARCH: {e}")
155
+
156
+ elif diagnostico == "Normalidade":
157
+ try:
158
+ jb_stat, jb_p, *_ = jarque_bera(serie.values.flatten())
159
+ if jb_p < alpha:
160
+ st.warning(f"Jarque-Bera: p-valor = {jb_p:.4f} < α → distribuição não normal")
161
+ else:
162
+ st.success(f"Jarque-Bera: p-valor = {jb_p:.4f} ≥ α → distribuição aproximadamente normal")
163
+ except Exception as e:
164
+ st.error(f"Erro no teste Jarque-Bera: {e}")
165
+
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Dockerfile para Diagnóstico de Séries Temporais com Streamlit
2
+
3
+ # syntax=docker/dockerfile:1
4
+
5
+ FROM python:3.10-slim
6
+
7
+ ENV PYTHONUNBUFFERED=1 \
8
+ PYTHONDONTWRITEBYTECODE=1
9
+
10
+ WORKDIR /app
11
+
12
+ # Copiar e instalar dependências
13
+ COPY requirements.txt .
14
+ RUN pip install --upgrade pip && pip install --no-cache-dir -r requirements.txt
15
+
16
+ # Copiar código e recursos
17
+ COPY Logo ./Logo
18
+ COPY Dashboard_Diagnostico_ST.py .
19
+
20
+ EXPOSE 8501
21
+
22
+ CMD ["streamlit", "run", "Dashboard_Diagnostico_ST.py", "--server.port=8501", "--server.enableCORS=false", "--server.address=0.0.0.0"]
23
+
Logo/MARCADOR.png ADDED
Logo/logo-est.png ADDED
Logo/logo_ppca.png ADDED
README.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: "Diagnóstico de Séries Temporais"
3
+ emoji: "📉"
4
+ colorFrom: "indigo"
5
+ colorTo: "green"
6
+ sdk: "docker"
7
+ app_file: "Dockerfile"
8
+ app_port: 8501
9
+ tags:
10
+ - streamlit
11
+ - séries temporais
12
+ - econometria
13
+ - testes estatísticos
14
+ - machine-learning
15
+ - finanças
16
+ - UnB
17
+ pinned: false
18
+ short_description: "Dashboard com testes de diagnóstico em séries temporais financeiras"
19
+ license: mit
20
+ ---
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ streamlit==1.32.0
2
+ pandas==2.2.2
3
+ numpy==1.26.4
4
+ plotly==5.18.0
5
+ yahooquery==2.3.7
6
+ scipy==1.13.1
7
+ pillow==9.4.0
8
+ statsmodels==0.14.1
9
+