FernandezUNB commited on
Commit
c1d5721
·
verified ·
1 Parent(s): 3d2bb08

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +286 -205
app.py CHANGED
@@ -1,220 +1,301 @@
1
  import gradio as gr
2
  import pandas as pd
 
3
  import numpy as np
 
4
  import plotly.express as px
5
  import plotly.graph_objects as go
6
- from scipy import optimize, stats
7
- from datetime import datetime
8
- import requests
9
  import warnings
 
 
 
 
10
  warnings.filterwarnings("ignore")
11
 
12
- # =====================
13
- # CONFIGURAÇÃO BRAPI
14
- # =====================
15
- BRAPI_API_KEY = "dCDdw4V35VedwMPBQCLM71" # Substitua pela sua chave válida
16
- BRAPI_HEADERS = {"Authorization": f"Bearer {BRAPI_API_KEY}"} if BRAPI_API_KEY else {}
17
- BRAPI_BASE_URL = "https://brapi.dev/api/quote"
18
-
19
- # =====================
20
- # CLASSE SIMULADOR
21
- # =====================
22
- class PortfolioSimulator:
23
- def __init__(self):
24
- self.available_stocks = {
25
- 'BBAS3': 'Banco do Brasil',
26
- 'ITSA4': 'Itaúsa',
27
- 'TAEE11': 'Taesa',
28
- 'TTEN3': '3tentos',
29
- 'BPAC11': 'BTG Pactual',
30
- 'PETR4': 'Petrobras',
31
- 'VALE3': 'Vale',
32
- 'ITUB4': 'Itaú Unibanco',
33
- 'BBDC4': 'Bradesco',
34
- 'WEGE3': 'WEG',
35
- 'MGLU3': 'Magazine Luiza',
36
- 'B3SA3': 'B3',
37
- 'RENT3': 'Localiza',
38
- 'ABEV3': 'Ambev',
39
- 'IBOV': 'IBOVESPA'
40
- }
41
-
42
- def download_data(self, tickers, start_date, end_date):
43
- df = pd.DataFrame()
44
- errors = []
45
- for ticker in tickers:
46
- try:
47
- # Adiciona .SA para tickers brasileiros, exceto IBOV
48
- api_ticker = f"{ticker}.SA" if ticker != 'IBOV' else ticker
49
- url = f"{BRAPI_BASE_URL}/{api_ticker}?range=5y&interval=1d"
50
- r = requests.get(url, headers=BRAPI_HEADERS, timeout=15)
51
- r.raise_for_status()
52
- data = r.json()
53
- if 'results' not in data or not data['results']:
54
- errors.append(f"{ticker}: Nenhum dado retornado pela API")
55
- continue
56
- historical = data['results'][0].get('historical', [])
57
- if not historical:
58
- errors.append(f"{ticker}: Nenhum dado histórico disponível")
59
- continue
60
- temp_df = pd.DataFrame(historical)
61
- temp_df['date'] = pd.to_datetime(temp_df['date'], errors='coerce')
62
- temp_df = temp_df.dropna(subset=['date', 'close'])
63
- temp_df = temp_df.set_index('date')
64
- df[ticker] = temp_df['close']
65
- print(f" {ticker} baixado com sucesso")
66
- except requests.exceptions.RequestException as e:
67
- errors.append(f"{ticker}: Erro de conexão - {str(e)}")
68
- except Exception as e:
69
- errors.append(f"{ticker}: Erro ao processar - {str(e)}")
70
-
71
- if df.empty:
72
- raise ValueError(f"Nenhum dado baixado. Erros: {'; '.join(errors)}")
73
-
74
- # Filtra pelo intervalo de datas e remove NaNs
75
- df = df.loc[start_date:end_date].dropna(how='all')
76
- if df.empty:
77
- raise ValueError(f"Nenhum dado disponível no intervalo {start_date} a {end_date}. Erros: {'; '.join(errors)}")
78
-
79
- return df, errors
80
-
81
- def calculate_returns(self, prices_df):
82
- returns = np.log(prices_df / prices_df.shift(1)).dropna()
83
- if returns.empty:
84
- raise ValueError("Não foi possível calcular retornos: dados insuficientes")
85
- return returns
86
-
87
- def monte_carlo_simulation(self, returns_df, num_simulations=50000):
88
- n_assets = len(returns_df.columns)
89
- all_weights = np.zeros((num_simulations, n_assets))
90
- ret_arr = np.zeros(num_simulations)
91
- vol_arr = np.zeros(num_simulations)
92
- sharpe_arr = np.zeros(num_simulations)
93
- mean_returns = returns_df.mean()
94
- cov_matrix = returns_df.cov()
95
-
96
- for i in range(num_simulations):
97
- weights = np.random.random(n_assets)
98
- weights /= np.sum(weights)
99
- all_weights[i, :] = weights
100
- ret_arr[i] = np.sum(weights * mean_returns)
101
- vol_arr[i] = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
102
- sharpe_arr[i] = ret_arr[i] / vol_arr[i] if vol_arr[i] > 0 else 0
103
- return all_weights, ret_arr, vol_arr, sharpe_arr
104
-
105
- def optimize_portfolio(self, returns_df):
106
- n_assets = len(returns_df.columns)
107
- mean_returns = returns_df.mean()
108
- cov_matrix = returns_df.cov()
109
-
110
- def negative_sharpe(weights):
111
- port_return = np.sum(weights * mean_returns)
112
- port_vol = np.sqrt(np.dot(weights.T, np.dot(cov_matrix, weights)))
113
- return -port_return / port_vol if port_vol > 0 else 0
114
-
115
- constraints = ({'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
116
- bounds = tuple((0, 1) for _ in range(n_assets))
117
- initial_guess = [1/n_assets] * n_assets
118
-
119
- result = optimize.minimize(
120
- negative_sharpe,
121
- initial_guess,
122
- method='SLSQP',
123
- bounds=bounds,
124
- constraints=constraints
125
- )
126
- return result.x
127
-
128
- def simulate_portfolio(self, prices_df, weights, initial_investment=35000):
129
- norm_prices = prices_df / prices_df.iloc[0]
130
- portfolio_value = (norm_prices * weights * initial_investment).sum(axis=1)
131
- portfolio_return = portfolio_value.pct_change().dropna()
132
- return portfolio_value, portfolio_return
133
-
134
- # =====================
135
- # FUNÇÃO PRINCIPAL
136
- # =====================
137
- def run_analysis(selected_stocks, num_simulations, initial_investment, start_date_str, end_date_str):
138
- simulator = PortfolioSimulator()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
139
  try:
140
- start_date = pd.to_datetime(start_date_str)
141
- end_date = pd.to_datetime(end_date_str)
142
- if not selected_stocks:
143
- return "❌ Selecione pelo menos uma ação", None, None, None, None
144
-
145
- prices_df, errors = simulator.download_data(selected_stocks, start_date, end_date)
146
- if errors:
147
- error_msg = f"Avisos: {'; '.join(errors)}\n"
148
- else:
149
- error_msg = ""
150
-
151
- returns_df = simulator.calculate_returns(prices_df)
152
- weights_mc, ret_arr, vol_arr, sharpe_arr = simulator.monte_carlo_simulation(returns_df, int(num_simulations))
153
- max_idx = np.argmax(sharpe_arr)
154
- optimal_weights = weights_mc[max_idx]
155
- portfolio_value, portfolio_return = simulator.simulate_portfolio(prices_df, optimal_weights, initial_investment)
156
-
157
- # ==== GRÁFICOS INTERATIVOS PLOTLY ====
158
- fig_weights = px.pie(names=selected_stocks, values=optimal_weights, title="Composição da Carteira Ótima")
159
- fig_evolution = go.Figure()
160
- fig_evolution.add_trace(go.Scatter(x=portfolio_value.index, y=portfolio_value.values, mode='lines', name='Patrimônio'))
161
- fig_evolution.update_layout(title='Evolução do Patrimônio', yaxis_title='Valor (R$)', xaxis_title='Data')
162
- fig_frontier = go.Figure()
163
- fig_frontier.add_trace(go.Scatter(x=vol_arr, y=ret_arr, mode='markers', marker=dict(color=sharpe_arr, colorscale='Viridis', showscale=True), name='Carteiras Simuladas'))
164
- fig_frontier.add_trace(go.Scatter(x=[vol_arr[max_idx]], y=[ret_arr[max_idx]], mode='markers', marker=dict(color='red', size=15, symbol='star'), name='Carteira Ótima'))
165
- fig_frontier.update_layout(title='Fronteira Eficiente', xaxis_title='Volatilidade', yaxis_title='Retorno')
166
- fig_prices = go.Figure()
167
- for stock in selected_stocks:
168
- fig_prices.add_trace(go.Scatter(x=prices_df.index, y=prices_df[stock], mode='lines', name=stock))
169
- fig_prices.update_layout(title='Preços das Ações', yaxis_title='Preço (R$)', xaxis_title='Data')
170
-
171
- result_text = f"""
172
- ## 📊 Resultados
173
- **Investimento Inicial:** R$ {initial_investment:,.2f}
174
- **Valor Final:** R$ {portfolio_value.iloc[-1]:,.2f}
175
- **Retorno Total:** {(portfolio_value.iloc[-1]/initial_investment - 1)*100:.2f}%
176
- {error_msg}
177
- """
178
- return result_text, fig_weights, fig_evolution, fig_frontier, fig_prices
179
  except Exception as e:
180
- return f"❌ Erro na simulação: {str(e)}", None, None, None, None
181
-
182
- # =====================
183
- # INTERFACE GRADIO
184
- # =====================
185
- simulator = PortfolioSimulator()
186
- with gr.Blocks(title="Simulador de Portfólio - BRAPI") as demo:
187
- gr.Markdown("# 🎯 Simulador de Portfólio - BRAPI")
188
- gr.Markdown("Selecione ações, ajuste parâmetros e visualize os resultados.")
189
- with gr.Row():
190
- with gr.Column():
191
- selected_stocks = gr.CheckboxGroup(
192
- label="Selecione as Ações",
193
- choices=list(simulator.available_stocks.keys()),
194
- value=['BBAS3', 'ITSA4', 'TAEE11']
195
- )
196
- num_simulations = gr.Slider(
197
- label="Número de Simulações",
198
- minimum=1000,
199
- maximum=200000,
200
- value=50000,
201
- step=1000
202
- )
203
- initial_investment = gr.Number(label="Investimento Inicial (R$)", value=35000)
204
- start_date = gr.Textbox(label="Data Inicial (YYYY-MM-DD)", value="2018-01-01")
205
- end_date = gr.Textbox(label="Data Final (YYYY-MM-DD)", value="2024-01-01")
206
- run_btn = gr.Button("🚀 Executar Simulação", variant="primary")
207
- with gr.Column():
208
- results_text = gr.Markdown()
209
  with gr.Row():
210
- pie_chart = gr.Plot(label="Composição da Carteira")
211
- evolution_plot = gr.Plot(label="Evolução do Patrimônio")
212
- efficient_frontier = gr.Plot(label="Fronteira Eficiente")
213
- prices_plot = gr.Plot(label="Preços das Ações")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  run_btn.click(
215
- fn=run_analysis,
216
- inputs=[selected_stocks, num_simulations, initial_investment, start_date, end_date],
217
- outputs=[results_text, pie_chart, evolution_plot, efficient_frontier, prices_plot]
218
  )
219
 
220
  if __name__ == "__main__":
 
1
  import gradio as gr
2
  import pandas as pd
3
+ import yfinance as yf
4
  import numpy as np
5
+ import matplotlib.pyplot as plt
6
  import plotly.express as px
7
  import plotly.graph_objects as go
8
+ import seaborn as sns
9
+ from scipy import stats, optimize
 
10
  import warnings
11
+ from io import BytesIO
12
+ import base64
13
+ from datetime import datetime
14
+
15
  warnings.filterwarnings("ignore")
16
 
17
+ # Default parameters from the notebook
18
+ default_tickers = ['BBAS3.SA', 'ITSA4.SA', 'TAEE11.SA', 'TTEN3.SA', 'BPAC11.SA', '^BVSP']
19
+ default_start_date = '2012-01-01'
20
+ default_end_date = '2024-07-31'
21
+ num_ports = 50000
22
+ initial_investment = 35000
23
+
24
+ # Fetch data
25
+ def fetch_data(tickers, start_date, end_date):
26
+ acoes_df = pd.DataFrame()
27
+ for acao in tickers:
28
+ try:
29
+ acoes_df[acao] = yf.download(acao, start=start_date, end=end_date, progress=False)['Close']
30
+ except Exception as e:
31
+ print(f"Error downloading {acao}: {e}")
32
+ acoes_df.index = acoes_df.index.strftime('%Y-%m-%d')
33
+ acoes_df.reset_index(inplace=True)
34
+ acoes_df.rename(columns={'index': 'Date'}, inplace=True)
35
+ return acoes_df
36
+
37
+ # Historical Prices Plot
38
+ def plot_historical_prices(acoes_df):
39
+ acoes_viz = acoes_df.copy()
40
+ figura = px.line(title='Histórico do Preço das Ações')
41
+ for i in acoes_viz.columns[1:]:
42
+ figura.add_scatter(x=acoes_viz["Date"], y=acoes_viz[i], name=i)
43
+ figura.update_layout(xaxis_title="Data", yaxis_title="Preço (R$)", hovermode='x unified')
44
+ return figura
45
+
46
+ # Returns Calculation and Plot
47
+ def calculate_and_plot_returns(acoes_df):
48
+ dataset = acoes_df.copy()
49
+ dataset.drop(labels=['Date'], axis=1, inplace=True)
50
+ taxas_retorno = np.log(dataset / dataset.shift(1))
51
+ date = acoes_df.filter(["Date"])
52
+ taxas_retorno = pd.concat([date, taxas_retorno], axis=1)
53
+ taxas_retorno = taxas_retorno.dropna()
54
+
55
+ figura = px.line(title='Histórico de Retorno das Ações')
56
+ for i in taxas_retorno.columns[1:]:
57
+ figura.add_scatter(x=taxas_retorno["Date"], y=taxas_retorno[i], name=i)
58
+ figura.update_layout(xaxis_title="Data", yaxis_title="Retorno Logarítmico", hovermode='x unified')
59
+
60
+ stats = taxas_retorno.describe().to_html()
61
+ return figura, stats
62
+
63
+ # Correlation Matrix
64
+ def plot_correlation_matrix(taxas_retorno):
65
+ correlacao_cols = taxas_retorno.select_dtypes(include=[np.number]).columns
66
+ correlacao = taxas_retorno[correlacao_cols].corr()
67
+ correlacao = np.round(correlacao, 2)
68
+ custom_colorscale = [[0.0, 'green'], [0.5, 'blue'], [1.0, 'red']]
69
+ fig = px.imshow(correlacao, text_auto=True, aspect="auto", color_continuous_scale=custom_colorscale,
70
+ labels=dict(color="Correlações"), zmin=-1, zmax=1, title="Matriz de Correlação dos Retornos")
71
+ return fig
72
+
73
+ # Efficient Frontier
74
+ def simulate_efficient_frontier(acoes_df, num_ports):
75
+ acoes_port = acoes_df.copy()
76
+ acoes_port.drop(labels=['^BVSP'], axis=1, inplace=True)
77
+ log_ret = acoes_port.copy()
78
+ log_ret.drop(labels=["Date"], axis=1, inplace=True)
79
+ log_ret = np.log(log_ret / log_ret.shift(1))
80
+ log_ret = log_ret.dropna()
81
+
82
+ np.random.seed(42)
83
+ all_weights = np.zeros((num_ports, len(acoes_port.columns[1:])))
84
+ ret_arr = np.zeros(num_ports)
85
+ vol_arr = np.zeros(num_ports)
86
+ sharpe_arr = np.zeros(num_ports)
87
+
88
+ for x in range(num_ports):
89
+ weights = np.array(np.random.random(5))
90
+ weights = weights / np.sum(weights)
91
+ all_weights[x, :] = weights
92
+ ret_arr[x] = np.sum((log_ret.mean() * weights))
93
+ vol_arr[x] = np.sqrt(np.dot(weights.T, np.dot(log_ret.cov(), weights)))
94
+ sharpe_arr[x] = ret_arr[x] / vol_arr[x]
95
+
96
+ melhores_pesos = all_weights[sharpe_arr.argmax(), :]
97
+ max_sr_vol = vol_arr[sharpe_arr.argmax()]
98
+ max_sr_ret = ret_arr[sharpe_arr.argmax()]
99
+
100
+ fig, ax = plt.subplots(figsize=(12, 8))
101
+ ax.scatter(vol_arr, ret_arr, c=sharpe_arr, cmap='viridis')
102
+ ax.scatter(max_sr_vol, max_sr_ret, c='red', s=200, marker='*', label='Carteira Ótima')
103
+ ax.set_xlabel('Volatilidade')
104
+ ax.set_ylabel('Retorno')
105
+ ax.set_title('Fronteira Eficiente - Simulação Monte Carlo')
106
+ ax.legend()
107
+ ax.grid(True, alpha=0.3)
108
+ buf = BytesIO()
109
+ fig.savefig(buf, format="png")
110
+ buf.seek(0)
111
+ img_base64 = base64.b64encode(buf.read()).decode('utf-8')
112
+ plt.close(fig)
113
+ return f'<img src="data:image/png;base64,{img_base64}">', melhores_pesos
114
+
115
+ # Portfolio Simulation
116
+ def simulate_portfolio(acoes_df, initial_investment, melhores_pesos):
117
+ dados_sim = acoes_df.copy()
118
+ if '^BVSP' in dados_sim.columns:
119
+ dados_sim = dados_sim.drop(columns=['^BVSP'])
120
+ datas = dados_sim['Date'].copy()
121
+ precos = dados_sim.drop(columns=['Date']).copy()
122
+
123
+ for col in precos.columns:
124
+ precos[col] = pd.to_numeric(precos[col], errors='coerce')
125
+ precos = precos.dropna()
126
+ datas = datas.iloc[:len(precos)].reset_index(drop=True)
127
+ precos = precos.reset_index(drop=True)
128
+
129
+ precos_norm = precos.copy()
130
+ for col in precos_norm.columns:
131
+ precos_norm[col] = precos_norm[col] / precos_norm[col].iloc[0]
132
+
133
+ portfolio_valores = pd.DataFrame()
134
+ portfolio_valores['Data'] = datas
135
+ nomes_ativos = ['BBAS3.SA', 'ITSA4.SA', 'TAEE11.SA', 'TTEN3.SA', 'BPAC11.SA']
136
+
137
+ for i, ativo in enumerate(nomes_ativos):
138
+ if ativo in precos_norm.columns:
139
+ portfolio_valores[ativo] = precos_norm[ativo] * melhores_pesos[i] * initial_investment
140
+
141
+ colunas_ativos = [col for col in portfolio_valores.columns if col != 'Data']
142
+ portfolio_valores['Valor_Total'] = portfolio_valores[colunas_ativos].sum(axis=1)
143
+ portfolio_valores['Retorno_Diario'] = 0.0
144
+
145
+ for i in range(1, len(portfolio_valores)):
146
+ valor_hoje = portfolio_valores['Valor_Total'].iloc[i]
147
+ valor_ontem = portfolio_valores['Valor_Total'].iloc[i-1]
148
+ if valor_ontem > 0:
149
+ portfolio_valores['Retorno_Diario'].iloc[i] = np.log(valor_hoje / valor_ontem) * 100
150
+
151
+ # Portfolio Evolution Plot
152
+ fig_evo = px.line(x=portfolio_valores['Data'], y=portfolio_valores['Valor_Total'],
153
+ title='Evolução do Patrimônio da Carteira',
154
+ labels={'x': 'Data', 'y': 'Valor (R$)'})
155
+ fig_evo.add_hline(y=portfolio_valores['Valor_Total'].mean(), line_color="green", line_dash="dot",
156
+ annotation_text="Valor Médio")
157
+ fig_evo.add_hline(y=initial_investment, line_color="red", line_dash="dot",
158
+ annotation_text=f"Investimento Inicial (R$ {initial_investment:,.0f})")
159
+
160
+ # Daily Returns Plot
161
+ fig_ret = px.line(x=portfolio_valores['Data'], y=portfolio_valores['Retorno_Diario'],
162
+ title='Retorno Diário do Portfólio',
163
+ labels={'x': 'Data', 'y': 'Retorno (%)'})
164
+ media_retorno = portfolio_valores['Retorno_Diario'].mean()
165
+ fig_ret.add_hline(y=media_retorno, line_color="red", line_dash="dot",
166
+ annotation_text=f"Retorno Médio: {media_retorno:.3f}%")
167
+
168
+ valor_final = portfolio_valores['Valor_Total'].iloc[-1]
169
+ return fig_evo, fig_ret, portfolio_valores, valor_final
170
+
171
+ # VaR Analysis
172
+ def analyze_var(portfolio_resultado, valor_final):
173
+ retornos_portfolio = portfolio_resultado['Retorno_Diario'].copy()[1:].dropna()
174
+
175
+ def calcular_var_historico(retornos, confianca):
176
+ percentil = (1 - confianca) * 100
177
+ return np.percentile(retornos, percentil)
178
+
179
+ var_95_historico = calcular_var_historico(retornos_portfolio, 0.95)
180
+ var_99_historico = calcular_var_historico(retornos_portfolio, 0.99)
181
+ var_95_money = valor_final * (np.exp(var_95_historico/100) - 1)
182
+ var_99_money = valor_final * (np.exp(var_99_historico/100) - 1)
183
+
184
+ def var_monte_carlo(retornos, num_simulacoes=10000, confianca=0.95):
185
+ np.random.seed(42)
186
+ media = retornos.mean()
187
+ desvio = retornos.std()
188
+ simulacoes = np.random.normal(media, desvio, num_simulacoes)
189
+ percentil = (1 - confianca) * 100
190
+ var_mc = np.percentile(simulacoes, percentil)
191
+ return var_mc, simulacoes
192
+
193
+ var_mc_95, simulacoes_95 = var_monte_carlo(retornos_portfolio, confianca=0.95)
194
+ var_mc_99, simulacoes_99 = var_monte_carlo(retornos_portfolio, confianca=0.99)
195
+ var_mc_95_money = valor_final * (np.exp(var_mc_95/100) - 1)
196
+ var_mc_99_money = valor_final * (np.exp(var_mc_99/100) - 1)
197
+
198
+ # VaR Plot
199
+ fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15, 6))
200
+ ax1.hist(retornos_portfolio, bins=50, alpha=0.7, color='skyblue', edgecolor='black', density=True)
201
+ ax1.axvline(var_95_historico, color='orange', linestyle='--', label=f'VaR 95%: {var_95_historico:.2f}%')
202
+ ax1.axvline(var_99_historico, color='red', linestyle='--', label=f'VaR 99%: {var_99_historico:.2f}%')
203
+ ax1.set_xlabel('Retorno Diário (%)')
204
+ ax1.set_ylabel('Densidade')
205
+ ax1.set_title('Distribuição dos Retornos Históricos\ncom VaR Histórico')
206
+ ax1.legend()
207
+ ax1.grid(True, alpha=0.3)
208
+
209
+ ax2.hist(simulacoes_95, bins=50, alpha=0.7, color='lightgreen', edgecolor='black', density=True)
210
+ ax2.axvline(var_mc_95, color='orange', linestyle='--', label=f'VaR MC 95%: {var_mc_95:.2f}%')
211
+ ax2.axvline(var_mc_99, color='red', linestyle='--', label=f'VaR MC 99%: {var_mc_99:.2f}%')
212
+ ax2.set_xlabel('Retorno Diário (%)')
213
+ ax2.set_ylabel('Densidade')
214
+ ax2.set_title('Distribuição Simulada (Monte Carlo)\ncom VaR Paramétrico')
215
+ ax2.legend()
216
+ ax2.grid(True, alpha=0.3)
217
+ plt.tight_layout()
218
+
219
+ buf = BytesIO()
220
+ fig.savefig(buf, format="png", dpi=300)
221
+ buf.seek(0)
222
+ img_base64 = base64.b64encode(buf.read()).decode('utf-8')
223
+ plt.close(fig)
224
+
225
+ # VaR Summary
226
+ var_summary = f"""
227
+ <h3>Resumo do VaR</h3>
228
+ <table border='1'>
229
+ <tr><th>Método</th><th>VaR 95% (1 dia)</th><th>VaR 99% (1 dia)</th></tr>
230
+ <tr><td>Histórico</td><td>{var_95_historico:.2f}% (R$ {abs(var_95_money):,.2f})</td><td>{var_99_historico:.2f}% (R$ {abs(var_99_money):,.2f})</td></tr>
231
+ <tr><td>Monte Carlo</td><td>{var_mc_95:.2f}% (R$ {abs(var_mc_95_money):,.2f})</td><td>{var_mc_99:.2f}% (R$ {abs(var_mc_99_money):,.2f})</td></tr>
232
+ </table>
233
+ """
234
+ return f'<img src="data:image/png;base64,{img_base64}">', var_summary
235
+
236
+ # Main Analysis Function
237
+ def run_analysis(tickers_str, start_date, end_date, num_simulations, investment):
238
  try:
239
+ tickers = [t.strip() for t in tickers_str.split(',')]
240
+ start_date = datetime.strptime(start_date, '%Y-%m-%d').strftime('%Y-%m-%d')
241
+ end_date = datetime.strptime(end_date, '%Y-%m-%d').strftime('%Y-%m-%d')
242
+ acoes_df = fetch_data(tickers, start_date, end_date)
243
+ if acoes_df.empty:
244
+ return [f"Error: No data fetched for {tickers}"] * 8
245
+
246
+ prices_plot = plot_historical_prices(acoes_df)
247
+ returns_plot, stats = calculate_and_plot_returns(acoes_df)
248
+ corr_plot = plot_correlation_matrix(pd.concat([acoes_df['Date'], np.log(acoes_df.drop('Date', axis=1) / acoes_df.drop('Date', axis=1).shift(1))], axis=1).dropna())
249
+ frontier_img, melhores_pesos = simulate_efficient_frontier(acoes_df, int(num_simulations))
250
+ port_evo, port_ret, portfolio_resultado, valor_final = simulate_portfolio(acoes_df, investment, melhores_pesos)
251
+ var_img, var_summary = analyze_var(portfolio_resultado, valor_final)
252
+
253
+ return prices_plot, returns_plot, corr_plot, frontier_img, port_evo, port_ret, var_img, stats + var_summary
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
  except Exception as e:
255
+ return [f"Error: {str(e)}"] * 8
256
+
257
+ # Gradio Interface
258
+ with gr.Blocks(title="Portfolio Analysis Dashboard") as demo:
259
+ gr.Markdown("# Portfolio Theory Visualization Dashboard")
260
+ gr.Markdown("Dynamic visualizations for portfolio analysis. Customize inputs and explore.")
261
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  with gr.Row():
263
+ tickers_input = gr.Textbox(label="Tickers (comma-separated)", value=','.join(default_tickers))
264
+ start_date = gr.Textbox(label="Start Date (YYYY-MM-DD)", value=default_start_date)
265
+ end_date = gr.Textbox(label="End Date (YYYY-MM-DD)", value=default_end_date)
266
+ num_sim = gr.Number(label="Number of Simulations", value=num_ports)
267
+ investment = gr.Number(label="Initial Investment (R$)", value=initial_investment)
268
+
269
+ run_btn = gr.Button("Run Analysis")
270
+
271
+ with gr.Tab("Historical Prices"):
272
+ prices_output = gr.Plot()
273
+
274
+ with gr.Tab("Returns History"):
275
+ returns_output = gr.Plot()
276
+
277
+ with gr.Tab("Correlation Matrix"):
278
+ corr_output = gr.Plot()
279
+
280
+ with gr.Tab("Efficient Frontier"):
281
+ frontier_output = gr.HTML()
282
+
283
+ with gr.Tab("Portfolio Evolution"):
284
+ port_evo_output = gr.Plot()
285
+
286
+ with gr.Tab("Daily Returns"):
287
+ port_ret_output = gr.Plot()
288
+
289
+ with gr.Tab("VaR Analysis"):
290
+ var_output = gr.HTML()
291
+
292
+ with gr.Tab("Statistics"):
293
+ stats_output = gr.HTML()
294
+
295
  run_btn.click(
296
+ run_analysis,
297
+ inputs=[tickers_input, start_date, end_date, num_sim, investment],
298
+ outputs=[prices_output, returns_output, corr_output, frontier_output, port_evo_output, port_ret_output, var_output, stats_output]
299
  )
300
 
301
  if __name__ == "__main__":