GLAkavya commited on
Commit
aed204c
Β·
verified Β·
1 Parent(s): 3dfaf87

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +322 -0
app.py ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ 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',
111
+ line=dict(width=3, color='red'),
112
+ name='Average Path'
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
+
258
+ with gr.Row():
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(
270
+ minimum=30,
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)