Brunohdez commited on
Commit
3f26f7e
·
verified ·
1 Parent(s): dc69291

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +290 -161
app.py CHANGED
@@ -4,21 +4,80 @@ import numpy as np
4
  import pandas as pd
5
  import datetime
6
  from scipy.stats import norm
7
- import matplotlib.pyplot as plt
8
  import plotly.graph_objects as go
9
 
10
  st.set_page_config(page_title="VaR & CVaR Calculator", layout="wide")
11
-
12
  st.title("📉 Portfolio VaR & CVaR Calculator")
13
  st.markdown("""
14
- Esta app permite calcular el **Valor en Riesgo (VaR)** y el **CVaR** para un portafolio de empresas, usando tres métodos: histórico, paramétrico y simulación Monte Carlo.
15
-
16
- 👉 Solo selecciona las empresas, rango de fechas y nivel de confianza.
17
  """)
18
 
19
- # -----------------------
20
- # Lista de empresas populares
21
- # -----------------------
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  company_options = {
23
  "Apple (AAPL)": "AAPL",
24
  "Tesla (TSLA)": "TSLA",
@@ -50,169 +109,239 @@ company_options = {
50
  "Walmart de México (WALMEX.MX)": "WALMEX.MX"
51
  }
52
 
53
- # -----------------------
54
- # Entradas del usuario
55
- # -----------------------
56
  with st.sidebar:
57
- st.header("🔧 Configuración del análisis")
58
  selected_companies = st.multiselect("Selecciona las empresas del portafolio", list(company_options.keys()))
59
  start_date = st.date_input("Fecha de inicio", datetime.date(2022, 1, 1))
60
  end_date = st.date_input("Fecha de fin", datetime.date.today())
61
  confidence_level = st.select_slider("Nivel de confianza", options=[0.90, 0.95, 0.99], value=0.95)
 
62
 
63
- # Obtener tickers directamente
64
  tickers = [company_options[c] for c in selected_companies]
65
 
 
 
 
66
  if st.button("📊 Calcular VaR y CVaR"):
67
  if not tickers:
68
  st.warning("⚠️ Debes seleccionar al menos una empresa.")
 
 
69
  else:
70
  with st.spinner("Obteniendo datos y calculando..."):
71
- data = yf.download(tickers, start=start_date, end=end_date)["Close"].dropna()
72
- returns = data.pct_change().dropna()
73
-
74
- if returns.empty:
75
- st.error("❌ No se encontraron datos válidos para el rango y empresas seleccionadas.")
76
- st.stop()
77
-
78
- # Pesos inversamente proporcionales a la volatilidad
79
- volatilities = returns.std()
80
- inv_vol = 1 / volatilities
81
- weights = inv_vol / inv_vol.sum()
82
-
83
- portfolio_returns = returns.dot(weights)
84
-
85
- if portfolio_returns.empty:
86
- st.error("❌ No se encontraron rendimientos válidos para el portafolio.")
87
- st.stop()
88
-
89
- tail_prob = 1 - confidence_level
90
-
91
- historical_VaR = np.percentile(portfolio_returns, tail_prob * 100)
92
- mean_ret = portfolio_returns.mean()
93
- std_ret = portfolio_returns.std()
94
- z_score = norm.ppf(tail_prob)
95
- parametric_VaR = mean_ret + z_score * std_ret
96
- simulated_returns = np.random.normal(mean_ret, std_ret, 10000)
97
- mc_VaR = np.percentile(simulated_returns, tail_prob * 100)
98
- historical_CVaR = portfolio_returns[portfolio_returns <= historical_VaR].mean()
99
-
100
- st.subheader("📌 Resultados del Portafolio")
101
- st.markdown(f"**Nivel de confianza:** {int(confidence_level * 100)}%")
102
- st.markdown("**Pesos calculados automáticamente en base a la volatilidad:**")
103
- st.dataframe(pd.DataFrame({"Ticker": tickers, "Peso": weights.values.round(4)}))
104
-
105
- col1, col2 = st.columns(2)
106
- with col1:
107
- st.metric("Retorno promedio diario", f"{mean_ret:.5f}")
108
- st.metric("Volatilidad diaria", f"{std_ret:.5f}")
109
- st.metric("VaR Histórico", f"{historical_VaR:.2%}")
110
- with col2:
111
- st.metric("VaR Paramétrico", f"{parametric_VaR:.2%}")
112
- st.metric("VaR Monte Carlo", f"{mc_VaR:.2%}")
113
- st.metric("CVaR Histórico", f"{historical_CVaR:.2%}")
114
-
115
- st.subheader("📊 Resultados Individuales por Empresa")
116
- individual_stats = []
117
- for ticker in tickers:
118
- r = returns[ticker]
119
- m = r.mean()
120
- s = r.std()
121
- hvar = np.percentile(r, tail_prob * 100)
122
- pvar = m + z_score * s
123
- sim_r = np.random.normal(m, s, 10000)
124
- mcvar = np.percentile(sim_r, tail_prob * 100)
125
- hcvar = r[r <= hvar].mean()
126
- individual_stats.append([
127
- ticker, m, s, hvar, pvar, mcvar, hcvar
128
- ])
129
-
130
- df_stats = pd.DataFrame(individual_stats, columns=[
131
- "Ticker", "Retorno Promedio", "Volatilidad", "VaR Histórico",
132
- "VaR Paramétrico", "VaR Monte Carlo", "CVaR Histórico"
133
- ])
134
- st.dataframe(df_stats.style.format({
135
- "Retorno Promedio": "{:.5f}",
136
- "Volatilidad": "{:.5f}",
137
- "VaR Histórico": "{:.2%}",
138
- "VaR Paramétrico": "{:.2%}",
139
- "VaR Monte Carlo": "{:.2%}",
140
- "CVaR Histórico": "{:.2%}"
141
- }))
142
-
143
- # 📊 Gráfica 1: Histograma de rendimientos del portafolio
144
- st.subheader("📉 Distribución de Rendimientos del Portafolio")
145
-
146
- hist_data = go.Histogram(
147
- x=portfolio_returns,
148
- nbinsx=50,
149
- name="Rendimientos",
150
- marker=dict(color='rgba(0, 123, 255, 0.6)'),
151
- hovertemplate='Rendimiento: %{x:.2%}<br>Frecuencia: %{y}'
152
- )
153
-
154
- vlines = []
155
- for value, label, color in zip(
156
- [historical_VaR, parametric_VaR, mc_VaR],
157
- ["VaR Histórico", "VaR Paramétrico", "VaR Monte Carlo"],
158
- ["red", "blue", "green"]
159
- ):
160
- vlines.append(go.Scatter(
161
- x=[value, value],
162
- y=[0, portfolio_returns.count() * 0.1],
163
- mode="lines",
164
- name=f"{label}: {value:.2%}",
165
- line=dict(dash="dash", color=color, width=2),
166
- showlegend=True
167
- ))
168
-
169
- fig = go.Figure([hist_data] + vlines)
170
- fig.update_layout(
171
- title="Distribución de Rendimientos del Portafolio",
172
- xaxis_title="Rendimiento Diario",
173
- yaxis_title="Frecuencia",
174
- template="plotly_white",
175
- hovermode="x unified",
176
- bargap=0.05,
177
- height=450
178
- )
179
- st.plotly_chart(fig, use_container_width=True)
180
-
181
- # 📈 Gráfica 2: Serie temporal
182
- st.subheader("📈 Serie Temporal de Rendimientos del Portafolio")
183
-
184
- fig2 = go.Figure()
185
- fig2.add_trace(go.Scatter(
186
- x=portfolio_returns.index,
187
- y=portfolio_returns,
188
- name="Rendimientos",
189
- mode="lines",
190
- line=dict(color="orange"),
191
- hovertemplate="Fecha: %{x}<br>Retorno: %{y:.2%}"
192
- ))
193
-
194
- for value, label, color in zip(
195
- [historical_VaR, parametric_VaR, mc_VaR],
196
- ["VaR Histórico", "VaR Paramétrico", "VaR Monte Carlo"],
197
- ["red", "blue", "green"]
198
- ):
199
- fig2.add_trace(go.Scatter(
200
- x=[portfolio_returns.index[0], portfolio_returns.index[-1]],
201
- y=[value, value],
202
- mode="lines",
203
- name=f"{label}: {value:.2%}",
204
- line=dict(dash="dash", color=color, width=2),
205
- showlegend=True
206
- ))
207
-
208
- fig2.update_layout(
209
- title="Rendimientos del Portafolio en el Tiempo",
210
- xaxis_title="Fecha",
211
- yaxis_title="Rendimiento Diario",
212
- template="plotly_white",
213
- hovermode="x unified",
214
- height=450
215
- )
216
- st.plotly_chart(fig2, use_container_width=True)
217
-
218
- st.success("✅ Cálculos completados exitosamente")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4
  import pandas as pd
5
  import datetime
6
  from scipy.stats import norm
 
7
  import plotly.graph_objects as go
8
 
9
  st.set_page_config(page_title="VaR & CVaR Calculator", layout="wide")
 
10
  st.title("📉 Portfolio VaR & CVaR Calculator")
11
  st.markdown("""
12
+ Esta app permite calcular el **Valor en Riesgo (VaR)** y el **CVaR** para un portafolio de empresas, usando tres métodos: histórico, paramétrico y simulación Monte Carlo.
13
+ 👉 Solo selecciona las empresas, rango de fechas, nivel de confianza y el número de simulaciones para el método Monte Carlo.
 
14
  """)
15
 
16
+ # -------------------------------------------------
17
+ # Funciones Auxiliares
18
+ # -------------------------------------------------
19
+ @st.cache_data
20
+ def fetch_data(tickers, start_date, end_date):
21
+ data = yf.download(tickers, start=start_date, end=end_date)["Close"]
22
+ return data.dropna()
23
+
24
+ def compute_weights(returns):
25
+ # Pesos inversamente proporcionales a la volatilidad
26
+ volatilidad = returns.std()
27
+ inv_vol = 1 / volatilidad
28
+ weights = inv_vol / inv_vol.sum()
29
+ return weights
30
+
31
+ def calculate_metrics(returns, confidence_level, n_simulations=10000):
32
+ tail_prob = 1 - confidence_level
33
+ portfolio_returns = returns.dot(compute_weights(returns))
34
+ mean_ret = portfolio_returns.mean()
35
+ std_ret = portfolio_returns.std()
36
+
37
+ # Cálculos para el portafolio
38
+ historical_VaR = np.percentile(portfolio_returns, tail_prob * 100)
39
+ z_score = norm.ppf(tail_prob)
40
+ parametric_VaR = mean_ret + z_score * std_ret
41
+ simulated_returns = np.random.normal(mean_ret, std_ret, n_simulations)
42
+ mc_VaR = np.percentile(simulated_returns, tail_prob * 100)
43
+ historical_CVaR = portfolio_returns[portfolio_returns <= historical_VaR].mean()
44
+
45
+ portfolio_metrics = {
46
+ "mean_return": mean_ret,
47
+ "std_return": std_ret,
48
+ "historical_VaR": historical_VaR,
49
+ "parametric_VaR": parametric_VaR,
50
+ "mc_VaR": mc_VaR,
51
+ "historical_CVaR": historical_CVaR,
52
+ "portfolio_returns": portfolio_returns
53
+ }
54
+ return portfolio_metrics
55
+
56
+ def calculate_individual_metrics(returns, tail_prob, z_score, n_simulations=10000):
57
+ stats = []
58
+ for ticker in returns.columns:
59
+ r = returns[ticker]
60
+ m = r.mean()
61
+ s = r.std()
62
+ hvar = np.percentile(r, tail_prob * 100)
63
+ pvar = m + z_score * s
64
+ sim_r = np.random.normal(m, s, n_simulations)
65
+ mcvar = np.percentile(sim_r, tail_prob * 100)
66
+ hcvar = r[r <= hvar].mean()
67
+ stats.append({
68
+ "Ticker": ticker,
69
+ "Retorno Promedio": m,
70
+ "Volatilidad": s,
71
+ "VaR Histórico": hvar,
72
+ "VaR Paramétrico": pvar,
73
+ "VaR Monte Carlo": mcvar,
74
+ "CVaR Histórico": hcvar
75
+ })
76
+ return pd.DataFrame(stats)
77
+
78
+ # -------------------------------------------------
79
+ # Configuración de la App (Sidebar)
80
+ # -------------------------------------------------
81
  company_options = {
82
  "Apple (AAPL)": "AAPL",
83
  "Tesla (TSLA)": "TSLA",
 
109
  "Walmart de México (WALMEX.MX)": "WALMEX.MX"
110
  }
111
 
 
 
 
112
  with st.sidebar:
113
+ st.header("🔧 Configuración del Análisis")
114
  selected_companies = st.multiselect("Selecciona las empresas del portafolio", list(company_options.keys()))
115
  start_date = st.date_input("Fecha de inicio", datetime.date(2022, 1, 1))
116
  end_date = st.date_input("Fecha de fin", datetime.date.today())
117
  confidence_level = st.select_slider("Nivel de confianza", options=[0.90, 0.95, 0.99], value=0.95)
118
+ n_simulations = st.number_input("Número de simulaciones Monte Carlo", min_value=1000, max_value=100000, value=10000, step=1000)
119
 
120
+ # Obtener tickers a partir de la selección
121
  tickers = [company_options[c] for c in selected_companies]
122
 
123
+ # -------------------------------------------------
124
+ # Ejecución y Cálculos
125
+ # -------------------------------------------------
126
  if st.button("📊 Calcular VaR y CVaR"):
127
  if not tickers:
128
  st.warning("⚠️ Debes seleccionar al menos una empresa.")
129
+ elif start_date >= end_date:
130
+ st.warning("⚠️ La fecha de inicio debe ser anterior a la fecha de fin.")
131
  else:
132
  with st.spinner("Obteniendo datos y calculando..."):
133
+ try:
134
+ data = fetch_data(tickers, start_date, end_date)
135
+ returns = data.pct_change().dropna()
136
+ if returns.empty:
137
+ st.error("❌ No se encontraron datos válidos para el rango y empresas seleccionadas.")
138
+ st.stop()
139
+
140
+ # Cálculo de métricas del portafolio y de cada empresa
141
+ weights = compute_weights(returns)
142
+ portfolio_metrics = calculate_metrics(returns, confidence_level, n_simulations)
143
+ tail_prob = 1 - confidence_level
144
+ z_score = norm.ppf(tail_prob)
145
+ df_individual = calculate_individual_metrics(returns, tail_prob, z_score, n_simulations)
146
+
147
+ # -------------------------------------------------
148
+ # Resultados del Portafolio
149
+ # -------------------------------------------------
150
+ st.subheader("📌 Resultados del Portafolio")
151
+ st.markdown(f"**Nivel de confianza:** {int(confidence_level * 100)}%")
152
+ st.markdown("**Pesos calculados automáticamente (inversamente proporcionales a la volatilidad):**")
153
+ weights_df = pd.DataFrame({
154
+ "Ticker": tickers,
155
+ "Peso": weights.round(4).values
156
+ })
157
+ st.dataframe(weights_df)
158
+
159
+ col1, col2 = st.columns(2)
160
+ with col1:
161
+ st.metric("Retorno promedio diario", f"{portfolio_metrics['mean_return']:.5f}")
162
+ st.metric("Volatilidad diaria", f"{portfolio_metrics['std_return']:.5f}")
163
+ st.metric("VaR Histórico", f"{portfolio_metrics['historical_VaR']:.2%}")
164
+ with col2:
165
+ st.metric("VaR Paramétrico", f"{portfolio_metrics['parametric_VaR']:.2%}")
166
+ st.metric("VaR Monte Carlo", f"{portfolio_metrics['mc_VaR']:.2%}")
167
+ st.metric("CVaR Histórico", f"{portfolio_metrics['historical_CVaR']:.2%}")
168
+
169
+ # -------------------------------------------------
170
+ # Resultados Individuales por Empresa
171
+ # -------------------------------------------------
172
+ st.subheader("📊 Resultados Individuales por Empresa")
173
+ df_individual_display = df_individual.style.format({
174
+ "Retorno Promedio": "{:.5f}",
175
+ "Volatilidad": "{:.5f}",
176
+ "VaR Histórico": "{:.2%}",
177
+ "VaR Paramétrico": "{:.2%}",
178
+ "VaR Monte Carlo": "{:.2%}",
179
+ "CVaR Histórico": "{:.2%}"
180
+ })
181
+ st.dataframe(df_individual_display)
182
+
183
+ # Botones para descargar resultados
184
+ csv_weights = weights_df.to_csv(index=False).encode('utf-8')
185
+ st.download_button("Descargar Pesos", csv_weights, "pesos_portafolio.csv", "text/csv")
186
+ csv_individual = df_individual.to_csv(index=False).encode('utf-8')
187
+ st.download_button("Descargar Resultados Individuales", csv_individual, "resultados_individuales.csv", "text/csv")
188
+
189
+ # -------------------------------------------------
190
+ # Creación de pestañas: una para el portafolio y otras para cada empresa
191
+ # -------------------------------------------------
192
+ tab_names = ["Portfolio"] + selected_companies
193
+ tabs = st.tabs(tab_names)
194
+
195
+ # --- Colores para el portafolio ---
196
+ portfolio_vaR_colors = ("tomato", "seagreen", "dodgerblue")
197
+
198
+ # ----- Tab: Portafolio -----
199
+ with tabs[0]:
200
+ st.markdown("## Gráficos del Portafolio")
201
+ # Histograma de Rendimientos del Portafolio con líneas de VaR
202
+ fig_port_hist = go.Figure()
203
+ fig_port_hist.add_trace(go.Histogram(
204
+ x=portfolio_metrics["portfolio_returns"],
205
+ nbinsx=50,
206
+ name="Rendimientos",
207
+ marker=dict(color='rgba(70, 130, 180, 0.6)'),
208
+ hovertemplate='Rendimiento: %{x:.2%}<br>Frecuencia: %{y}'
209
+ ))
210
+ for value, label, color in zip(
211
+ [portfolio_metrics["historical_VaR"],
212
+ portfolio_metrics["parametric_VaR"],
213
+ portfolio_metrics["mc_VaR"]],
214
+ ["VaR Histórico", "VaR Paramétrico", "VaR Monte Carlo"],
215
+ portfolio_vaR_colors
216
+ ):
217
+ fig_port_hist.add_trace(go.Scatter(
218
+ x=[value, value],
219
+ y=[0, portfolio_metrics["portfolio_returns"].count() * 0.1],
220
+ mode="lines",
221
+ name=f"{label}: {value:.2%}",
222
+ line=dict(dash="dash", color=color, width=2)
223
+ ))
224
+ fig_port_hist.update_layout(
225
+ title="Distribución de Rendimientos del Portafolio",
226
+ xaxis_title="Rendimiento Diario",
227
+ yaxis_title="Frecuencia",
228
+ template="plotly_white",
229
+ hovermode="x unified",
230
+ bargap=0.05,
231
+ height=450
232
+ )
233
+ st.plotly_chart(fig_port_hist, use_container_width=True)
234
+
235
+ # Serie Temporal de Rendimientos del Portafolio
236
+ fig_port_line = go.Figure()
237
+ fig_port_line.add_trace(go.Scatter(
238
+ x=portfolio_metrics["portfolio_returns"].index,
239
+ y=portfolio_metrics["portfolio_returns"],
240
+ name="Rendimientos",
241
+ mode="lines",
242
+ line=dict(color="orange"),
243
+ hovertemplate="Fecha: %{x}<br>Retorno: %{y:.2%}"
244
+ ))
245
+ for value, label, color in zip(
246
+ [portfolio_metrics["historical_VaR"],
247
+ portfolio_metrics["parametric_VaR"],
248
+ portfolio_metrics["mc_VaR"]],
249
+ ["VaR Histórico", "VaR Paramétrico", "VaR Monte Carlo"],
250
+ portfolio_vaR_colors
251
+ ):
252
+ fig_port_line.add_trace(go.Scatter(
253
+ x=[portfolio_metrics["portfolio_returns"].index[0],
254
+ portfolio_metrics["portfolio_returns"].index[-1]],
255
+ y=[value, value],
256
+ mode="lines",
257
+ name=f"{label}: {value:.2%}",
258
+ line=dict(dash="dash", color=color, width=2)
259
+ ))
260
+ fig_port_line.update_layout(
261
+ title="Serie Temporal de Rendimientos del Portafolio",
262
+ xaxis_title="Fecha",
263
+ yaxis_title="Rendimiento Diario",
264
+ template="plotly_white",
265
+ hovermode="x unified",
266
+ height=450
267
+ )
268
+ st.plotly_chart(fig_port_line, use_container_width=True)
269
+
270
+ # --- Paleta de colores para empresas (d3 Category10) ---
271
+ category_colors = ["#1f77b4", "#ff7f0e", "#2ca02c", "#d62728",
272
+ "#9467bd", "#8c564b", "#e377c2", "#7f7f7f",
273
+ "#bcbd22", "#17becf"]
274
+
275
+ # ----- Tabs: Gráficos Individuales de cada Empresa -----
276
+ for i, company in enumerate(selected_companies):
277
+ ticker = company_options[company]
278
+ # Extraer los valores del VaR para la empresa desde df_individual
279
+ company_metrics = df_individual[df_individual["Ticker"] == ticker].iloc[0]
280
+ # Asignar colores distintos para la empresa usando la paleta
281
+ comp_hist_color = category_colors[i % len(category_colors)]
282
+ comp_param_color = category_colors[(i+1) % len(category_colors)]
283
+ comp_mc_color = category_colors[(i+2) % len(category_colors)]
284
+
285
+ with tabs[i+1]:
286
+ st.markdown(f"### {company}")
287
+ # Primero, el histograma de rendimientos (gráfica de barras)
288
+ fig_hist = go.Figure()
289
+ fig_hist.add_trace(go.Histogram(
290
+ x=returns[ticker],
291
+ nbinsx=50,
292
+ name="Rendimientos",
293
+ marker=dict(color=comp_hist_color, opacity=0.6),
294
+ hovertemplate='Rendimiento: %{x:.2%}<br>Frecuencia: %{y}'
295
+ ))
296
+ for value, label, color in zip(
297
+ [company_metrics["VaR Histórico"], company_metrics["VaR Paramétrico"], company_metrics["VaR Monte Carlo"]],
298
+ ["VaR Histórico", "VaR Paramétrico", "VaR Monte Carlo"],
299
+ [comp_hist_color, comp_param_color, comp_mc_color]
300
+ ):
301
+ fig_hist.add_trace(go.Scatter(
302
+ x=[value, value],
303
+ y=[0, returns[ticker].count() * 0.1],
304
+ mode="lines",
305
+ name=f"{label}: {value:.2%}",
306
+ line=dict(dash="dash", color=color, width=2)
307
+ ))
308
+ fig_hist.update_layout(
309
+ title=f"{company}: Distribución de Rendimientos",
310
+ xaxis_title="Rendimiento",
311
+ yaxis_title="Frecuencia",
312
+ template="plotly_white",
313
+ bargap=0.05
314
+ )
315
+ st.plotly_chart(fig_hist, use_container_width=True)
316
+
317
+ # Luego, la serie de precios (gráfica de líneas)
318
+ fig_price = go.Figure()
319
+ fig_price.add_trace(go.Scatter(
320
+ x=data.index,
321
+ y=data[ticker],
322
+ mode="lines",
323
+ name="Precio de Cierre",
324
+ hovertemplate="Fecha: %{x}<br>Precio: %{y:.2f}"
325
+ ))
326
+ fig_price.update_layout(
327
+ title=f"{company}: Serie de Precios",
328
+ xaxis_title="Fecha",
329
+ yaxis_title="Precio (USD)",
330
+ template="plotly_white"
331
+ )
332
+ st.plotly_chart(fig_price, use_container_width=True)
333
+
334
+ st.success("✅ Cálculos completados exitosamente")
335
+
336
+ # -------------------------------------------------
337
+ # Explicación de los Métodos de Cálculo
338
+ # -------------------------------------------------
339
+ with st.expander("ℹ️ Más información sobre los métodos de cálculo"):
340
+ st.markdown("""
341
+ **VaR Histórico:** Calcula el percentil de los rendimientos históricos.
342
+ **VaR Paramétrico:** Utiliza la media, la desviación estándar y la distribución normal (z-score) para estimar el VaR.
343
+ **VaR Monte Carlo:** Simula rendimientos usando una distribución normal basada en la media y la desviación estándar del portafolio.
344
+ **CVaR Histórico:** Es el promedio de los rendimientos que están por debajo del VaR histórico.
345
+ """)
346
+ except Exception as e:
347
+ st.error(f"❌ Ocurrió un error durante el cálculo: {e}")