GLAkavya commited on
Commit
adea40e
Β·
verified Β·
1 Parent(s): 4463ff2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +220 -139
app.py CHANGED
@@ -3,108 +3,124 @@ import pandas as pd
3
  import numpy as np
4
  import plotly.graph_objects as go
5
  import plotly.express as px
6
- from plotly.subplots import make_subplots
7
  import yfinance as yf
8
  from datetime import datetime, timedelta
9
  import pickle
10
- import json
11
  import warnings
12
  warnings.filterwarnings('ignore')
13
 
14
- # Load trained model
15
  def load_model():
16
  try:
17
  with open('portfolio_risk_model.pkl', 'rb') as f:
18
  model = pickle.load(f)
 
 
19
  return model
20
  except Exception as e:
21
- print(f"Model loading error: {str(e)}")
22
  return None
23
 
24
  class GradioRiskApp:
25
  def __init__(self):
26
  self.model = load_model()
27
- self.available_stocks = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA',
28
- 'META', 'NVDA', 'NFLX', 'JPM', 'JNJ',
29
- 'V', 'PG', 'DIS', 'BAC', 'XOM']
 
 
30
 
31
- def get_current_data(self, symbols, period='1y'):
32
- """Get current stock data"""
33
  try:
34
- data = yf.download(symbols, period=period)['Adj Close']
35
- return data
36
- except Exception as e:
37
- print(f"Data fetch error: {str(e)}")
38
- return None
39
-
40
- def run_monte_carlo(self, weights, days=252, simulations=5000):
41
- """Run Monte Carlo simulation with given weights"""
42
- if self.model is None:
43
- return None
44
 
45
- mean_returns = np.array(self.model['mean_returns'])
46
- cov_matrix = np.array(self.model['covariance_matrix'])
47
-
48
- # Generate simulation
49
- np.random.seed(42)
50
- try:
51
- L = np.linalg.cholesky(cov_matrix)
52
- except:
53
- eigvals, eigvecs = np.linalg.eigh(cov_matrix)
54
- L = eigvecs @ np.diag(np.sqrt(eigvals))
55
-
56
- simulation_results = []
57
- for _ in range(simulations):
58
- random_numbers = np.random.normal(0, 1, size=(days, len(mean_returns)))
59
- correlated_randoms = random_numbers @ L.T
60
- daily_returns = correlated_randoms + mean_returns
61
 
62
- portfolio_value = 100
63
- portfolio_path = [portfolio_value]
 
64
 
65
- for day in range(days):
66
- daily_portfolio_return = np.dot(daily_returns[day], weights)
67
- portfolio_value *= (1 + daily_portfolio_return)
68
- portfolio_path.append(portfolio_value)
 
 
 
 
69
 
70
- simulation_results.append(portfolio_path)
71
-
72
- return np.array(simulation_results)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
 
74
  def calculate_metrics(self, simulation_results):
75
  """Calculate risk metrics from simulation"""
76
- final_values = simulation_results[:, -1]
 
 
 
 
77
 
78
  metrics = {
79
  'expected_value': np.mean(final_values),
80
- 'median_value': np.median(final_values),
81
- 'std_value': np.std(final_values),
82
  'prob_10_loss': np.mean(final_values < 90),
83
  'prob_20_loss': np.mean(final_values < 80),
84
  'prob_30_loss': np.mean(final_values < 70),
85
  'var_95': np.percentile(final_values, 5),
86
  'best_case': np.percentile(final_values, 95),
87
- 'worst_case': np.percentile(final_values, 5)
 
88
  }
89
 
90
- return metrics
91
 
92
  def create_simulation_plot(self, simulation_results):
93
  """Create Monte Carlo simulation plot"""
 
 
 
94
  fig = go.Figure()
95
 
96
- # Sample paths
97
- for i in range(min(50, len(simulation_results))):
98
  fig.add_trace(go.Scatter(
99
  y=simulation_results[i],
100
  mode='lines',
101
- line=dict(width=1, color='blue'),
102
- opacity=0.1,
103
  showlegend=False
104
  ))
105
 
106
  # Mean path
107
- mean_path = simulation_results.mean(axis=0)
108
  fig.add_trace(go.Scatter(
109
  y=mean_path,
110
  mode='lines',
@@ -113,145 +129,193 @@ class GradioRiskApp:
113
  ))
114
 
115
  fig.update_layout(
116
- title="Monte Carlo Simulation Paths",
117
  xaxis_title="Trading Days",
118
  yaxis_title="Portfolio Value ($)",
119
- height=400
 
120
  )
121
 
122
  return fig
123
 
124
  def create_distribution_plot(self, simulation_results, metrics):
125
  """Create final value distribution plot"""
126
- final_values = simulation_results[:, -1]
 
 
 
127
 
128
  fig = px.histogram(
129
  x=final_values,
130
  nbins=50,
131
- title="Distribution of Final Portfolio Values",
132
  color_discrete_sequence=['#FF6B6B']
133
  )
134
 
135
- fig.add_vline(x=metrics['expected_value'], line_dash="dash", line_color="red",
136
- annotation_text=f"Mean: ${metrics['expected_value']:.2f}")
137
- fig.add_vline(x=metrics['var_95'], line_dash="dash", line_color="orange",
138
- annotation_text=f"5% VaR: ${metrics['var_95']:.2f}")
 
139
 
140
  fig.update_layout(height=400, showlegend=False)
141
-
142
  return fig
143
 
144
  def create_risk_gauge(self, metrics):
145
  """Create risk probability gauge"""
 
 
 
146
  risk_prob = metrics['prob_10_loss'] * 100
147
 
148
  fig = go.Figure(go.Indicator(
149
- mode = "gauge+number+delta",
150
  value = risk_prob,
151
  domain = {'x': [0, 1], 'y': [0, 1]},
152
- title = {'text': "Probability of >10% Loss"},
153
  gauge = {
154
  'axis': {'range': [None, 50]},
155
- 'bar': {'color': "darkblue"},
156
  'steps': [
157
- {'range': [0, 10], 'color': "lightgreen"},
158
- {'range': [10, 25], 'color': "yellow"},
159
- {'range': [25, 50], 'color': "red"}],
160
  'threshold': {
161
- 'line': {'color': "red", 'width': 4},
162
  'thickness': 0.75,
163
- 'value': 30}}
164
  ))
165
  fig.update_layout(height=300)
166
-
167
  return fig
168
 
169
  def analyze_portfolio(self, selected_stocks, simulation_days, num_simulations):
170
- """Main analysis function for Gradio"""
 
 
171
  if not selected_stocks:
172
- return "Please select at least one stock", None, None, None, None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
173
 
174
  try:
175
- # Equal weights for selected stocks
176
- n_stocks = len(selected_stocks)
177
- weights = [1/n_stocks] * n_stocks
178
 
179
  # Run simulation
180
- simulation_results = self.run_monte_carlo(weights, simulation_days, num_simulations)
181
 
182
  if simulation_results is None:
183
- return "Error in simulation", None, None, None, None
 
 
 
 
 
 
184
 
185
  # Calculate metrics
186
- metrics = self.calculate_metrics(simulation_results)
 
 
 
 
 
 
 
 
 
187
 
188
  # Create plots
189
  sim_plot = self.create_simulation_plot(simulation_results)
190
  dist_plot = self.create_distribution_plot(simulation_results, metrics)
191
  risk_gauge = self.create_risk_gauge(metrics)
192
 
193
- # Create metrics summary
 
 
 
194
  summary_html = f"""
195
- <div style="font-family: Arial, sans-serif; padding: 20px; background: #f5f5f5; border-radius: 10px;">
196
- <h2 style="color: #333; text-align: center;">πŸ“Š Portfolio Risk Analysis Report</h2>
197
 
198
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin-top: 20px;">
199
- <div style="background: white; padding: 15px; border-radius: 8px; border-left: 4px solid #4CAF50;">
200
- <h3 style="margin: 0; color: #666;">Expected Value</h3>
201
- <p style="font-size: 24px; font-weight: bold; color: #333; margin: 5px 0;">${metrics['expected_value']:.2f}</p>
 
 
 
 
 
 
202
  </div>
203
 
204
- <div style="background: white; padding: 15px; border-radius: 8px; border-left: 4px solid #FF9800;">
205
- <h3 style="margin: 0; color: #666;">Value at Risk (95%)</h3>
206
- <p style="font-size: 24px; font-weight: bold; color: #333; margin: 5px 0;">${metrics['var_95']:.2f}</p>
207
  </div>
208
 
209
- <div style="background: white; padding: 15px; border-radius: 8px; border-left: 4px solid #F44336;">
210
- <h3 style="margin: 0; color: #666;">10% Loss Probability</h3>
211
- <p style="font-size: 24px; font-weight: bold; color: #333; margin: 5px 0;">{metrics['prob_10_loss']*100:.1f}%</p>
212
  </div>
213
 
214
- <div style="background: white; padding: 15px; border-radius: 8px; border-left: 4px solid #2196F3;">
215
- <h3 style="margin: 0; color: #666;">Best Case (95%)</h3>
216
- <p style="font-size: 24px; font-weight: bold; color: #333; margin: 5px 0;">${metrics['best_case']:.2f}</p>
217
  </div>
218
  </div>
219
 
220
- <div style="margin-top: 20px;">
221
- <h3 style="color: #333;">Portfolio Composition:</h3>
222
- <p style="color: #666;">{', '.join(selected_stocks)}</p>
223
- <p style="color: #666;">Equal weights: {', '.join([f'{w*100:.1f}%' for w in weights])}</p>
 
224
  </div>
225
  </div>
226
  """
227
 
228
- return summary_html, sim_plot, dist_plot, risk_gauge, None
 
229
 
230
  except Exception as e:
231
- return f"Error in analysis: {str(e)}", None, None, None, None
 
 
 
 
 
 
 
 
232
 
233
- # Initialize the app
234
  app = GradioRiskApp()
235
 
236
- # Custom CSS for better styling
237
- custom_css = """
238
- .gradio-container {
239
- font-family: 'Arial', sans-serif;
240
- }
241
- .container {
242
- max-width: 1200px;
243
- margin: 0 auto;
244
- }
245
- """
246
-
247
  # Create Gradio interface
248
- with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
249
  gr.Markdown(
250
  """
251
- # πŸ“Š QuantRisk Pro - Portfolio Risk Analyzer
252
- **AI-Powered Monte Carlo Simulations for Portfolio Risk Assessment**
253
 
254
- *Analyze your stock portfolio risk using advanced probabilistic models*
255
  """
256
  )
257
 
@@ -259,11 +323,16 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
259
  with gr.Column(scale=1):
260
  gr.Markdown("### πŸ”§ Portfolio Configuration")
261
 
 
 
 
 
 
262
  stock_checkboxes = gr.CheckboxGroup(
263
  choices=app.available_stocks,
264
- value=['AAPL', 'MSFT', 'GOOGL'],
265
- label="Select Stocks for Portfolio",
266
- info="Choose up to 10 stocks"
267
  )
268
 
269
  simulation_days = gr.Slider(
@@ -271,52 +340,64 @@ with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo:
271
  maximum=500,
272
  value=252,
273
  step=30,
274
- label="Time Horizon (Days)",
275
- info="Simulation period in trading days"
276
  )
277
 
278
- num_simulations = gr.Radio(
279
  choices=[1000, 2500, 5000, 10000],
280
  value=5000,
281
- label="Number of Simulations",
282
- info="More simulations = more accuracy"
283
  )
284
 
285
- analyze_btn = gr.Button("πŸš€ Run Risk Analysis", variant="primary")
 
 
 
 
 
 
 
 
 
286
 
287
  with gr.Column(scale=2):
288
  gr.Markdown("### πŸ“ˆ Analysis Results")
289
 
290
  summary_html = gr.HTML(
291
- label="Risk Summary",
292
- value="<div style='text-align: center; color: #666; padding: 50px;'>Configure your portfolio and click 'Run Risk Analysis' to see results</div>"
 
 
 
 
 
293
  )
294
 
295
  with gr.Row():
296
- risk_gauge = gr.Plot(label="Risk Probability Gauge")
297
- simulation_plot = gr.Plot(label="Monte Carlo Simulation")
298
 
299
- with gr.Row():
300
- distribution_plot = gr.Plot(label="Value Distribution")
301
 
302
  # Footer
 
303
  gr.Markdown(
304
  """
305
- ---
306
  <div style="text-align: center; color: #666;">
307
- <p>Built with ❀️ using Gradio | QuantRisk Pro v1.0</p>
308
- <p>Uses Monte Carlo simulations and historical data for risk assessment</p>
309
  </div>
310
  """
311
  )
312
 
313
- # Set up the analysis function
314
  analyze_btn.click(
315
  fn=app.analyze_portfolio,
316
  inputs=[stock_checkboxes, simulation_days, num_simulations],
317
  outputs=[summary_html, simulation_plot, distribution_plot, risk_gauge]
318
  )
319
 
320
- # Launch the app
321
  if __name__ == "__main__":
322
- demo.launch(share=True)
 
3
  import numpy as np
4
  import plotly.graph_objects as go
5
  import plotly.express as px
 
6
  import yfinance as yf
7
  from datetime import datetime, timedelta
8
  import pickle
 
9
  import warnings
10
  warnings.filterwarnings('ignore')
11
 
12
+ # Load trained model - USING YOUR SPECIFIC STOCKS
13
  def load_model():
14
  try:
15
  with open('portfolio_risk_model.pkl', 'rb') as f:
16
  model = pickle.load(f)
17
+ print("βœ… Model loaded successfully!")
18
+ print(f"πŸ“Š Model trained on: {model['tickers']}")
19
  return model
20
  except Exception as e:
21
+ print(f"❌ Model loading error: {str(e)}")
22
  return None
23
 
24
  class GradioRiskApp:
25
  def __init__(self):
26
  self.model = load_model()
27
+
28
+ # USE EXACTLY THE SAME 5 STOCKS YOU TRAINED WITH
29
+ self.available_stocks = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA']
30
+
31
+ print(f"🎯 Using trained stocks: {self.available_stocks}")
32
 
33
+ def run_monte_carlo(self, selected_stocks, days=252, simulations=5000):
34
+ """Run Monte Carlo simulation using the trained model"""
35
  try:
36
+ if self.model is None:
37
+ return "❌ Model not loaded properly", None, None, None
 
 
 
 
 
 
 
 
38
 
39
+ # Check if selected stocks match trained stocks
40
+ if set(selected_stocks) != set(self.available_stocks):
41
+ return f"❌ Please use exactly these 5 stocks: {self.available_stocks}", None, None, None
42
+
43
+ n_stocks = len(selected_stocks)
44
+ print(f"🎯 Running MC simulation for {selected_stocks}...")
 
 
 
 
 
 
 
 
 
 
45
 
46
+ # Use the trained model parameters
47
+ mean_returns = np.array(self.model['mean_returns'])
48
+ cov_matrix = np.array(self.model['covariance_matrix'])
49
 
50
+ # Generate simulation
51
+ np.random.seed(42)
52
+ try:
53
+ L = np.linalg.cholesky(cov_matrix)
54
+ except:
55
+ # Use eigenvalue decomposition if Cholesky fails
56
+ eigvals, eigvecs = np.linalg.eigh(cov_matrix)
57
+ L = eigvecs @ np.diag(np.sqrt(np.maximum(eigvals, 0)))
58
 
59
+ simulation_results = []
60
+ equal_weights = np.array([0.2, 0.2, 0.2, 0.2, 0.2]) # Equal weights for 5 stocks
61
+
62
+ for i in range(simulations):
63
+ random_numbers = np.random.normal(0, 1, size=(days, n_stocks))
64
+ correlated_randoms = random_numbers @ L.T
65
+ daily_returns = correlated_randoms + mean_returns
66
+
67
+ portfolio_value = 100
68
+ portfolio_path = [portfolio_value]
69
+
70
+ for day in range(days):
71
+ daily_portfolio_return = np.dot(daily_returns[day], equal_weights)
72
+ portfolio_value *= (1 + daily_portfolio_return)
73
+ portfolio_path.append(portfolio_value)
74
+
75
+ simulation_results.append(portfolio_path)
76
+
77
+ print(f"βœ… Simulation completed: {len(simulation_results)} paths")
78
+ return simulation_results
79
+
80
+ except Exception as e:
81
+ print(f"❌ Simulation error: {str(e)}")
82
+ return None
83
 
84
  def calculate_metrics(self, simulation_results):
85
  """Calculate risk metrics from simulation"""
86
+ if simulation_results is None:
87
+ return None
88
+
89
+ simulation_array = np.array(simulation_results)
90
+ final_values = simulation_array[:, -1]
91
 
92
  metrics = {
93
  'expected_value': np.mean(final_values),
 
 
94
  'prob_10_loss': np.mean(final_values < 90),
95
  'prob_20_loss': np.mean(final_values < 80),
96
  'prob_30_loss': np.mean(final_values < 70),
97
  'var_95': np.percentile(final_values, 5),
98
  'best_case': np.percentile(final_values, 95),
99
+ 'worst_case': np.percentile(final_values, 5),
100
+ 'median_value': np.median(final_values)
101
  }
102
 
103
+ return metrics, simulation_array
104
 
105
  def create_simulation_plot(self, simulation_results):
106
  """Create Monte Carlo simulation plot"""
107
+ if simulation_results is None:
108
+ return None
109
+
110
  fig = go.Figure()
111
 
112
+ # Show only 30 paths for clarity
113
+ for i in range(min(30, len(simulation_results))):
114
  fig.add_trace(go.Scatter(
115
  y=simulation_results[i],
116
  mode='lines',
117
+ line=dict(width=1, color='lightblue'),
118
+ opacity=0.3,
119
  showlegend=False
120
  ))
121
 
122
  # Mean path
123
+ mean_path = np.mean(simulation_results, axis=0)
124
  fig.add_trace(go.Scatter(
125
  y=mean_path,
126
  mode='lines',
 
129
  ))
130
 
131
  fig.update_layout(
132
+ title="πŸ“ˆ Monte Carlo Simulation Paths",
133
  xaxis_title="Trading Days",
134
  yaxis_title="Portfolio Value ($)",
135
+ height=400,
136
+ showlegend=True
137
  )
138
 
139
  return fig
140
 
141
  def create_distribution_plot(self, simulation_results, metrics):
142
  """Create final value distribution plot"""
143
+ if simulation_results is None:
144
+ return None
145
+
146
+ final_values = np.array(simulation_results)[:, -1]
147
 
148
  fig = px.histogram(
149
  x=final_values,
150
  nbins=50,
151
+ title="πŸ“Š Distribution of Final Portfolio Values",
152
  color_discrete_sequence=['#FF6B6B']
153
  )
154
 
155
+ if metrics:
156
+ fig.add_vline(x=metrics['expected_value'], line_dash="dash", line_color="red",
157
+ annotation_text=f"Mean: ${metrics['expected_value']:.2f}")
158
+ fig.add_vline(x=metrics['var_95'], line_dash="dash", line_color="orange",
159
+ annotation_text=f"Worst 5%: ${metrics['var_95']:.2f}")
160
 
161
  fig.update_layout(height=400, showlegend=False)
 
162
  return fig
163
 
164
  def create_risk_gauge(self, metrics):
165
  """Create risk probability gauge"""
166
+ if metrics is None:
167
+ return None
168
+
169
  risk_prob = metrics['prob_10_loss'] * 100
170
 
171
  fig = go.Figure(go.Indicator(
172
+ mode = "gauge+number",
173
  value = risk_prob,
174
  domain = {'x': [0, 1], 'y': [0, 1]},
175
+ title = {'text': "πŸ”΄ Probability of >10% Loss"},
176
  gauge = {
177
  'axis': {'range': [None, 50]},
178
+ 'bar': {'color': "darkred"},
179
  'steps': [
180
+ {'range': [0, 15], 'color': "lightgreen"},
181
+ {'range': [15, 30], 'color': "yellow"},
182
+ {'range': [30, 50], 'color': "red"}],
183
  'threshold': {
184
+ 'line': {'color': "black", 'width': 4},
185
  'thickness': 0.75,
186
+ 'value': 25}}
187
  ))
188
  fig.update_layout(height=300)
 
189
  return fig
190
 
191
  def analyze_portfolio(self, selected_stocks, simulation_days, num_simulations):
192
+ """Main analysis function"""
193
+ print(f"πŸ” Analyzing portfolio: {selected_stocks}")
194
+
195
  if not selected_stocks:
196
+ error_html = """
197
+ <div style='text-align: center; padding: 50px; background: #fff3cd; border-radius: 10px;'>
198
+ <h3 style='color: #856404;'>⚠️ Please Select Stocks</h3>
199
+ <p>Choose at least one stock from the list to run the analysis.</p>
200
+ </div>
201
+ """
202
+ return error_html, None, None, None
203
+
204
+ # Check if user selected exactly the 5 trained stocks
205
+ if set(selected_stocks) != set(self.available_stocks):
206
+ error_html = f"""
207
+ <div style='text-align: center; padding: 50px; background: #fff3cd; border-radius: 10px;'>
208
+ <h3 style='color: #856404;'>⚠️ Use Trained Stocks Only</h3>
209
+ <p>This model was trained specifically on these 5 stocks:</p>
210
+ <p style='font-weight: bold; font-size: 18px;'>{', '.join(self.available_stocks)}</p>
211
+ <p>Please select <strong>all 5 stocks</strong> for accurate risk analysis.</p>
212
+ </div>
213
+ """
214
+ return error_html, None, None, None
215
 
216
  try:
217
+ # Convert simulations to integer
218
+ num_simulations = int(num_simulations)
 
219
 
220
  # Run simulation
221
+ simulation_results = self.run_monte_carlo(selected_stocks, simulation_days, num_simulations)
222
 
223
  if simulation_results is None:
224
+ error_html = """
225
+ <div style='text-align: center; padding: 50px; background: #f8d7da; border-radius: 10px;'>
226
+ <h3 style='color: #721c24;'>❌ Simulation Failed</h3>
227
+ <p>Unable to run simulation. Please try again.</p>
228
+ </div>
229
+ """
230
+ return error_html, None, None, None
231
 
232
  # Calculate metrics
233
+ metrics, simulation_array = self.calculate_metrics(simulation_results)
234
+
235
+ if metrics is None:
236
+ error_html = """
237
+ <div style='text-align: center; padding: 50px; background: #f8d7da; border-radius: 10px;'>
238
+ <h3 style='color: #721c24;'>❌ Metrics Calculation Failed</h3>
239
+ <p>Unable to calculate risk metrics.</p>
240
+ </div>
241
+ """
242
+ return error_html, None, None, None
243
 
244
  # Create plots
245
  sim_plot = self.create_simulation_plot(simulation_results)
246
  dist_plot = self.create_distribution_plot(simulation_results, metrics)
247
  risk_gauge = self.create_risk_gauge(metrics)
248
 
249
+ # Create success summary
250
+ risk_level = "LOW" if metrics['prob_10_loss'] < 0.15 else "MEDIUM" if metrics['prob_10_loss'] < 0.3 else "HIGH"
251
+ risk_color = "#28a745" if risk_level == "LOW" else "#ffc107" if risk_level == "MEDIUM" else "#dc3545"
252
+
253
  summary_html = f"""
254
+ <div style="font-family: Arial, sans-serif; padding: 25px; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); border-radius: 15px; color: white;">
255
+ <h2 style="text-align: center; margin-bottom: 30px;">πŸ“Š Portfolio Risk Analysis Report</h2>
256
 
257
+ <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 10px; margin-bottom: 20px;">
258
+ <h3 style="margin-top: 0;">🎯 Trained Portfolio Analysis</h3>
259
+ <p style="font-size: 18px; font-weight: bold;">{', '.join(selected_stocks)}</p>
260
+ <p>Equal weights (20% each) β€’ {simulation_days} days β€’ {num_simulations} simulations</p>
261
+ </div>
262
+
263
+ <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 15px;">
264
+ <div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
265
+ <h4 style="margin: 0;">Expected Value</h4>
266
+ <p style="font-size: 24px; font-weight: bold; margin: 5px 0;">${metrics['expected_value']:.2f}</p>
267
  </div>
268
 
269
+ <div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
270
+ <h4 style="margin: 0;">Risk Level</h4>
271
+ <p style="font-size: 24px; font-weight: bold; margin: 5px 0; color: {risk_color};">{risk_level}</p>
272
  </div>
273
 
274
+ <div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
275
+ <h4 style="margin: 0;">10% Loss Probability</h4>
276
+ <p style="font-size: 24px; font-weight: bold; margin: 5px 0;">{metrics['prob_10_loss']*100:.1f}%</p>
277
  </div>
278
 
279
+ <div style="background: rgba(255,255,255,0.2); padding: 15px; border-radius: 8px;">
280
+ <h4 style="margin: 0;">Worst Case (5%)</h4>
281
+ <p style="font-size: 24px; font-weight: bold; margin: 5px 0;">${metrics['var_95']:.2f}</p>
282
  </div>
283
  </div>
284
 
285
+ <div style="margin-top: 20px; background: rgba(255,255,255,0.1); padding: 15px; border-radius: 8px;">
286
+ <h4>πŸ“ˆ Additional Metrics</h4>
287
+ <p>20% Loss Probability: <strong>{metrics['prob_20_loss']*100:.1f}%</strong> |
288
+ 30% Loss Probability: <strong>{metrics['prob_30_loss']*100:.1f}%</strong> |
289
+ Best Case (95%): <strong>${metrics['best_case']:.2f}</strong></p>
290
  </div>
291
  </div>
292
  """
293
 
294
+ print("βœ… Analysis completed successfully!")
295
+ return summary_html, sim_plot, dist_plot, risk_gauge
296
 
297
  except Exception as e:
298
+ error_html = f"""
299
+ <div style='text-align: center; padding: 50px; background: #f8d7da; border-radius: 10px;'>
300
+ <h3 style='color: #721c24;'>❌ Analysis Error</h3>
301
+ <p>Error: {str(e)}</p>
302
+ <p>Please try again.</p>
303
+ </div>
304
+ """
305
+ print(f"❌ Analysis error: {str(e)}")
306
+ return error_html, None, None, None
307
 
308
+ # Initialize app
309
  app = GradioRiskApp()
310
 
 
 
 
 
 
 
 
 
 
 
 
311
  # Create Gradio interface
312
+ with gr.Blocks(theme=gr.themes.Soft(), title="QuantRisk Pro") as demo:
313
  gr.Markdown(
314
  """
315
+ # πŸ“Š QuantRisk Pro - Portfolio Risk Analyzer
316
+ **AI-Powered Monte Carlo Simulations for Portfolio Risk Assessment**
317
 
318
+ *Model trained on: AAPL, MSFT, GOOGL, AMZN, TSLA (5 years historical data)*
319
  """
320
  )
321
 
 
323
  with gr.Column(scale=1):
324
  gr.Markdown("### πŸ”§ Portfolio Configuration")
325
 
326
+ gr.Markdown("""
327
+ **🎯 Trained Stock Portfolio**
328
+ *This model was specifically trained on these 5 stocks*
329
+ """)
330
+
331
  stock_checkboxes = gr.CheckboxGroup(
332
  choices=app.available_stocks,
333
+ value=app.available_stocks, # Auto-select all 5 stocks
334
+ label="**Select Stocks (Choose ALL 5)**",
335
+ info="Model works only with these specific stocks"
336
  )
337
 
338
  simulation_days = gr.Slider(
 
340
  maximum=500,
341
  value=252,
342
  step=30,
343
+ label="**Time Horizon (Days)**",
344
+ info="Simulation period in trading days (252 = 1 year)"
345
  )
346
 
347
+ num_simulations = gr.Dropdown(
348
  choices=[1000, 2500, 5000, 10000],
349
  value=5000,
350
+ label="**Number of Simulations**",
351
+ info="More simulations = more accuracy but slower"
352
  )
353
 
354
+ analyze_btn = gr.Button("πŸš€ Run Risk Analysis", variant="primary", size="lg")
355
+
356
+ gr.Markdown("---")
357
+ gr.Markdown("""
358
+ **πŸ’‘ Important Notes:**
359
+ - βœ… Model trained on 5 years of AAPL, MSFT, GOOGL, AMZN, TSLA data
360
+ - βœ… Uses actual historical volatility and correlations
361
+ - βœ… All 5 stocks must be selected for accurate results
362
+ - βœ… Equal weights (20% each) applied automatically
363
+ """)
364
 
365
  with gr.Column(scale=2):
366
  gr.Markdown("### πŸ“ˆ Analysis Results")
367
 
368
  summary_html = gr.HTML(
369
+ value=f"""
370
+ <div style='text-align: center; padding: 50px; background: #f8f9fa; border-radius: 10px;'>
371
+ <h3 style='color: #6c757d;'>πŸš€ Ready to Analyze!</h3>
372
+ <p>Model trained on: <strong>{', '.join(app.available_stocks)}</strong></p>
373
+ <p>All 5 stocks are pre-selected. Click 'Run Risk Analysis' to see your risk report.</p>
374
+ </div>
375
+ """
376
  )
377
 
378
  with gr.Row():
379
+ risk_gauge = gr.Plot(label="**Risk Probability Gauge**")
380
+ simulation_plot = gr.Plot(label="**Monte Carlo Simulation**")
381
 
382
+ distribution_plot = gr.Plot(label="**Portfolio Value Distribution**")
 
383
 
384
  # Footer
385
+ gr.Markdown("---")
386
  gr.Markdown(
387
  """
 
388
  <div style="text-align: center; color: #666;">
389
+ <p>Built with ❀️ using Gradio | QuantRisk Pro v2.0 | Trained on 5 years of historical data</p>
 
390
  </div>
391
  """
392
  )
393
 
394
+ # Set up event handling
395
  analyze_btn.click(
396
  fn=app.analyze_portfolio,
397
  inputs=[stock_checkboxes, simulation_days, num_simulations],
398
  outputs=[summary_html, simulation_plot, distribution_plot, risk_gauge]
399
  )
400
 
401
+ # Launch for Hugging Face
402
  if __name__ == "__main__":
403
+ demo.launch()