-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
419 lines (331 loc) Β· 13.3 KB
/
Copy pathapp.py
File metadata and controls
419 lines (331 loc) Β· 13.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
import streamlit as st
import numpy as np
import pandas as pd
from datetime import datetime
from ui.portfolio_builder import portfolio_builder
from ui.modern_components import (
display_header_with_animation,
display_metric_cards,
display_section_header,
display_insight_box,
display_collapsible_section,
create_gradient_chart,
display_portfolio_summary,
display_stat_row,
display_progress_bar,
display_enhanced_insights
)
from simulations.monte_carlo import run_monte_carlo
from simulations.historical import run_historical_simulation
from simulations.bootstrap import run_bootstrap_simulation
from simulations.stress_test import run_stress_test
from utils.data_fetcher import fetch_price_data, validate_portfolio_alignment
from utils.explanations import (
get_simulation_explanations,
get_personalized_var_explanation,
get_personalized_es_explanation,
get_personalized_graph_explanation,
get_simulation_comparison
)
from utils.styling import inject_custom_css
from utils.pdf_generator import generate_pdf_report, get_pdf_filename
# FIX: Configure page
st.set_page_config(
page_title="Quantfolio Simulation Hub",
page_icon="π",
layout="wide",
initial_sidebar_state="expanded"
)
# FIX: Inject custom CSS
inject_custom_css()
# FIX: Display animated header
display_header_with_animation()
# FIX: Add introduction info box
display_insight_box(
title="Welcome to Quantfolio",
content="Use advanced simulation techniques to understand your portfolio's risk profile. Choose your stocks, run simulations, and get personalized risk insights.",
icon="π",
box_type="info"
)
# ============================================
# SIDEBAR - Portfolio Management
# ============================================
st.sidebar.markdown("---")
with st.sidebar.expander("π Learn About Simulations", expanded=False):
st.markdown("""
This tool helps you understand your portfolio's risk using 4 different simulation methods.
Each method shows you possible outcomes and helps you make informed decisions.
**Choose your preferred method:**
- **Monte Carlo** - Most comprehensive
- **Historical** - Most realistic
- **Bootstrap** - Balanced approach
- **Stress Test** - Worst-case scenario
""")
portfolio_df = portfolio_builder()
st.sidebar.markdown("---")
st.sidebar.subheader("βοΈ Simulation Settings")
simulation_model = st.sidebar.selectbox(
"Simulation Model",
["Monte Carlo", "Historical Simulation", "Bootstrap Simulation", "Stress Test"],
help="Choose the simulation method that best fits your needs"
)
# FIX: Map simulation model names to dictionary keys
model_key_map = {
"Monte Carlo": "Monte Carlo",
"Historical Simulation": "Historical",
"Bootstrap Simulation": "Bootstrap",
"Stress Test": "Stress"
}
# FIX: Add simulation explanation
simulations = get_simulation_explanations()
model_key = model_key_map[simulation_model]
with st.sidebar.expander(f"βΉοΈ About {simulation_model}"):
sim_info = simulations[model_key]
st.markdown(sim_info["title"])
st.markdown(sim_info["what_is_it"])
st.markdown(sim_info["how_it_works"])
st.markdown(sim_info["why_useful"])
st.markdown(sim_info["best_for"])
iterations = st.sidebar.slider(
"Number of Simulations",
1000,
50000,
10000,
step=1000,
help="More simulations = more accurate but slower"
)
confidence = st.sidebar.slider(
"Confidence Level (%)",
90,
99,
95,
help="How confident you want to be about the VaR estimate"
)
st.sidebar.markdown("---")
run_button = st.sidebar.button(
"π Run Simulation",
use_container_width=True,
help="Click to run the selected simulation"
)
# ============================================
# MAIN CONTENT - Portfolio Analysis
# ============================================
if run_button and portfolio_df is not None:
stocks = portfolio_df["Stock"].tolist()
quantities = portfolio_df["Quantity"].values
# Show loading state
with st.spinner("π₯ Fetching market data..."):
try:
data = fetch_price_data(stocks)
except ValueError as e:
st.error(f"β Error fetching data: {e}")
st.stop()
# FIX: Use validation function for proper alignment
aligned_portfolio_df, valid_stocks, excluded_stocks = validate_portfolio_alignment(
portfolio_df,
data.columns.tolist()
)
# FIX: Check if we have any valid stocks left
if len(valid_stocks) == 0:
st.error("β No valid stocks available for simulation. Please check your portfolio.")
st.stop()
# FIX: Update quantities array to match aligned portfolio
quantities = aligned_portfolio_df["Quantity"].values
stocks = aligned_portfolio_df["Stock"].tolist()
# FIX: Filter data to only include valid stocks (in same order as portfolio)
data = data[stocks]
# Final validation
if len(quantities) != len(data.columns):
st.error(f"β Data mismatch: {len(quantities)} quantities but {len(data.columns)} stocks")
st.stop()
# Calculate portfolio value
prices = aligned_portfolio_df["Price"].values
portfolio_value = np.sum(prices * quantities)
# Display portfolio summary with aligned data
display_portfolio_summary(aligned_portfolio_df, portfolio_value)
st.markdown("---")
# Run simulation with progress indicator
display_section_header("π Running Simulation", "")
col1, col2 = st.columns([3, 1])
with col1:
st.info(f"π {simulation_model} with {len(stocks)} stocks and {iterations:,} iterations")
with col2:
st.info(f"πΌ Portfolio: βΉ{portfolio_value:,.0f}")
try:
with st.spinner(f"β³ Running {simulation_model}..."):
if simulation_model == "Monte Carlo":
losses = run_monte_carlo(data, quantities, iterations)
elif simulation_model == "Historical Simulation":
losses = run_historical_simulation(data, quantities)
elif simulation_model == "Bootstrap Simulation":
losses = run_bootstrap_simulation(data, quantities, iterations)
else:
losses = run_stress_test(data, quantities)
# Calculate metrics
var = np.percentile(losses, 100 - confidence)
es = losses[losses <= var].mean()
st.success("β
Simulation completed successfully!")
st.markdown("---")
# FIX: Display results with metric cards
display_section_header("π Risk Analysis Results", "")
display_metric_cards(var, es, confidence)
st.markdown("---")
# FIX: Display detailed insights
display_section_header("π Detailed Insights", "")
col1, col2 = st.columns(2)
with col1:
display_stat_row(
label="Worst Case Loss",
value=f"βΉ{losses.max():,.0f}",
icon="π",
color="danger"
)
display_stat_row(
label="Best Case Gain",
value=f"βΉ{abs(losses.min()):,.0f}",
icon="π",
color="success"
)
with col2:
max_loss_pct = (losses.max() / portfolio_value) * 100
display_progress_bar(
"Maximum Risk Exposure",
max_loss_pct,
max_value=100,
color="danger"
)
safe_scenarios = (losses <= var).sum()
safe_pct = (safe_scenarios / len(losses)) * 100
display_progress_bar(
"Safe Scenarios",
safe_pct,
max_value=100,
color="success"
)
st.markdown("---")
# FIX: Display chart with professional styling
display_section_header("π Loss Distribution Chart", "")
# Create gradient chart
fig = create_gradient_chart(losses, var, confidence)
st.plotly_chart(fig, use_container_width=True)
st.markdown("---")
# FIX: Display educational explanations in collapsible sections
display_section_header("π Understanding Your Results", "")
col1, col2 = st.columns([2, 1])
with col1:
display_collapsible_section(
"π° What is Value at Risk (VaR)?",
get_personalized_var_explanation(portfolio_value, var, confidence, losses),
icon="π°",
is_open=True
)
display_collapsible_section(
"π What is Expected Shortfall (ES)?",
get_personalized_es_explanation(portfolio_value, var, es, confidence, losses),
icon="π",
is_open=False
)
display_collapsible_section(
"π How to Read the Graph?",
get_personalized_graph_explanation(portfolio_value, var, confidence, losses),
icon="π",
is_open=False
)
with col2:
display_insight_box(
title="Pro Tips",
content="""
β
**Run all simulations** to compare results
β
**Monitor trends** over time
β
**Diversify** to reduce risk
β
**Rebalance** regularly
""",
icon="π‘",
box_type="success"
)
st.markdown("---")
# FIX: Display export options
display_section_header("π₯ Export Results", "")
col1, col2 = st.columns(2)
with col1:
# PDF download button
# FIX: Get explanations first
var_explanation = get_personalized_var_explanation(portfolio_value, var, confidence, losses)
es_explanation = get_personalized_es_explanation(portfolio_value, var, es, confidence, losses)
graph_explanation = get_personalized_graph_explanation(portfolio_value, var, confidence, losses)
pdf_buffer = generate_pdf_report(
aligned_portfolio_df,
portfolio_value,
var,
es,
confidence,
losses,
simulation_model,
len(stocks),
var_explanation=var_explanation,
es_explanation=es_explanation,
graph_explanation=graph_explanation
)
st.download_button(
label="π Download PDF Report",
data=pdf_buffer,
file_name=get_pdf_filename(),
mime="application/pdf",
help="Download comprehensive simulation report as PDF"
)
with col2:
# CSV export
csv_data = pd.DataFrame({
"Loss Scenarios": losses
}).to_csv(index=False)
st.download_button(
label="π Download CSV Data",
data=csv_data,
file_name=f"quantfolio_data_{datetime.now().strftime('%Y%m%d_%H%M%S')}.csv",
mime="text/csv",
help="Download raw simulation data as CSV"
)
st.markdown("---")
# Display enhanced insights
display_section_header("πΌ Personalized Insights", "")
display_enhanced_insights(var, es, confidence, losses, portfolio_value)
except Exception as e:
st.error(f"β Error during simulation: {e}")
print(f"Error details: {str(e)}")
st.stop()
else:
if portfolio_df is None:
display_insight_box(
title="Get Started",
content="π **Step 1:** Build or upload your portfolio from the sidebar\n\nπ **Step 2:** Configure simulation settings\n\nπ **Step 3:** Click 'Run Simulation' to see your risk analysis",
icon="π",
box_type="info"
)
st.markdown("---")
# FIX: Add comparison and glossary
with st.expander("π Compare All Simulation Methods"):
st.markdown(get_simulation_comparison())
with st.expander("π Financial Terms Glossary"):
glossary = """
**Portfolio**: All your investments combined
**Volatility**: How much a stock's price jumps up and down
**Risk**: The chance of losing money
**Distribution**: How outcomes are spread (concentrated vs scattered)
**Confidence Level**: How sure you want to be (95% means 95% certainty)
**Scenario**: A possible outcome or simulation run
**Historical Data**: Actual price movements from the past
**Correlation**: How two stocks move together (or apart)
**Tail Risk**: The risk of extreme, unexpected losses
**Stress Test**: Testing portfolio under worst-case conditions
**Value at Risk (VaR)**: Maximum expected loss at a given confidence level
**Expected Shortfall**: Average loss in worst-case scenarios
"""
st.markdown(glossary)
# Footer
st.markdown("---")
st.markdown("""
<div style='text-align: center; color: #6b7280; font-size: 0.9rem; padding: 20px;'>
<p>πΌ Quantfolio Simulation Hub | Advanced Portfolio Risk Analysis</p>
<p>β οΈ Disclaimer: This tool is for educational and analytical purposes. Past performance doesn't guarantee future results.</p>
</div>
""", unsafe_allow_html=True)