FernandezUNB commited on
Commit
7e0fb21
·
verified ·
1 Parent(s): 208a0a7

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +69 -27
app.py CHANGED
@@ -12,8 +12,9 @@ warnings.filterwarnings("ignore")
12
  # =====================
13
  # CONFIGURAÇÃO BRAPI
14
  # =====================
15
- BRAPI_API_KEY = "dCDdw4V35VedwMPBQCLM71" # Coloque sua chave aqui
16
  BRAPI_HEADERS = {"Authorization": f"Bearer {BRAPI_API_KEY}"} if BRAPI_API_KEY else {}
 
17
 
18
  # =====================
19
  # CLASSE SIMULADOR
@@ -40,24 +41,48 @@ class PortfolioSimulator:
40
 
41
  def download_data(self, tickers, start_date, end_date):
42
  df = pd.DataFrame()
 
43
  for ticker in tickers:
44
  try:
45
- url = f"https://brapi.dev/api/quote/{ticker}?range=5y&interval=1d"
46
- r = requests.get(url, headers=BRAPI_HEADERS, timeout=10)
 
 
47
  r.raise_for_status()
48
- data = r.json().get('results', [])[0]['historical']
49
- temp_df = pd.DataFrame(data)
50
- temp_df['date'] = pd.to_datetime(temp_df['date'])
 
 
 
 
 
 
 
 
51
  temp_df = temp_df.set_index('date')
52
  df[ticker] = temp_df['close']
53
- print(f"✓ {ticker} baixado via BRAPI")
 
 
54
  except Exception as e:
55
- print(f" Erro ao baixar {ticker} via BRAPI: {e}")
56
- df = df[start_date:end_date].dropna()
57
- return df
 
 
 
 
 
 
 
 
58
 
59
  def calculate_returns(self, prices_df):
60
- return np.log(prices_df / prices_df.shift(1)).dropna()
 
 
 
61
 
62
  def monte_carlo_simulation(self, returns_df, num_simulations=50000):
63
  n_assets = len(returns_df.columns)
@@ -114,23 +139,26 @@ def run_analysis(selected_stocks, num_simulations, initial_investment, start_dat
114
  try:
115
  start_date = pd.to_datetime(start_date_str)
116
  end_date = pd.to_datetime(end_date_str)
117
- if not isinstance(selected_stocks, list):
118
- selected_stocks = [selected_stocks]
119
- prices_df = simulator.download_data(selected_stocks, start_date, end_date)
120
- returns_df = simulator.calculate_returns(prices_df)
 
 
 
 
121
 
122
- weights_mc, ret_arr, vol_arr, sharpe_arr = simulator.monte_carlo_simulation(returns_df, num_simulations)
 
123
  max_idx = np.argmax(sharpe_arr)
124
  optimal_weights = weights_mc[max_idx]
125
-
126
- math_weights = simulator.optimize_portfolio(returns_df)
127
  portfolio_value, portfolio_return = simulator.simulate_portfolio(prices_df, optimal_weights, initial_investment)
128
 
129
  # ==== GRÁFICOS INTERATIVOS PLOTLY ====
130
  fig_weights = px.pie(names=selected_stocks, values=optimal_weights, title="Composição da Carteira Ótima")
131
  fig_evolution = go.Figure()
132
  fig_evolution.add_trace(go.Scatter(x=portfolio_value.index, y=portfolio_value.values, mode='lines', name='Patrimônio'))
133
- fig_evolution.update_layout(title='Evolução do Patrimônio', yaxis_title='Valor (R$)')
134
  fig_frontier = go.Figure()
135
  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'))
136
  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'))
@@ -138,18 +166,18 @@ def run_analysis(selected_stocks, num_simulations, initial_investment, start_dat
138
  fig_prices = go.Figure()
139
  for stock in selected_stocks:
140
  fig_prices.add_trace(go.Scatter(x=prices_df.index, y=prices_df[stock], mode='lines', name=stock))
141
- fig_prices.update_layout(title='Preços das Ações', yaxis_title='Preço')
142
 
143
  result_text = f"""
144
  ## 📊 Resultados
145
  **Investimento Inicial:** R$ {initial_investment:,.2f}
146
  **Valor Final:** R$ {portfolio_value.iloc[-1]:,.2f}
147
  **Retorno Total:** {(portfolio_value.iloc[-1]/initial_investment - 1)*100:.2f}%
 
148
  """
149
-
150
  return result_text, fig_weights, fig_evolution, fig_frontier, fig_prices
151
  except Exception as e:
152
- return f"❌ Erro na simulação: {e}", None, None, None, None
153
 
154
  # =====================
155
  # INTERFACE GRADIO
@@ -157,10 +185,21 @@ def run_analysis(selected_stocks, num_simulations, initial_investment, start_dat
157
  simulator = PortfolioSimulator()
158
  with gr.Blocks(title="Simulador de Portfólio - BRAPI") as demo:
159
  gr.Markdown("# 🎯 Simulador de Portfólio - BRAPI")
 
160
  with gr.Row():
161
  with gr.Column():
162
- selected_stocks = gr.CheckboxGroup(label="Selecione as Ações", choices=list(simulator.available_stocks.keys()), value=['BBAS3','ITSA4','TAEE11'])
163
- num_simulations = gr.Slider(label="Número de Simulações", minimum=1000, maximum=200000, value=50000, step=1000)
 
 
 
 
 
 
 
 
 
 
164
  initial_investment = gr.Number(label="Investimento Inicial (R$)", value=35000)
165
  start_date = gr.Textbox(label="Data Inicial (YYYY-MM-DD)", value="2018-01-01")
166
  end_date = gr.Textbox(label="Data Final (YYYY-MM-DD)", value="2024-01-01")
@@ -172,8 +211,11 @@ with gr.Blocks(title="Simulador de Portfólio - BRAPI") as demo:
172
  evolution_plot = gr.Plot(label="Evolução do Patrimônio")
173
  efficient_frontier = gr.Plot(label="Fronteira Eficiente")
174
  prices_plot = gr.Plot(label="Preços das Ações")
175
- run_btn.click(fn=run_analysis, inputs=[selected_stocks, num_simulations, initial_investment, start_date, end_date],
176
- outputs=[results_text, pie_chart, evolution_plot, efficient_frontier, prices_plot])
 
 
 
177
 
178
  if __name__ == "__main__":
179
- demo.launch(share=True)
 
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
 
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)
 
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'))
 
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
 
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")
 
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__":
221
+ demo.launch()