GLAkavya commited on
Commit
a12ab2c
Β·
verified Β·
1 Parent(s): d9028d3

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +158 -216
app.py CHANGED
@@ -1,243 +1,185 @@
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
  import yfinance as yf
7
- import warnings
8
- warnings.filterwarnings('ignore')
 
9
 
10
- class FreshRiskApp:
11
- def __init__(self):
12
- # Hardcoded stock names to avoid encoding issues
13
- self.stock_list = [
14
- "AAPL - Apple",
15
- "MSFT - Microsoft",
16
- "GOOGL - Google",
17
- "AMZN - Amazon",
18
- "TSLA - Tesla",
19
- "META - Meta",
20
- "NVDA - NVIDIA",
21
- "NFLX - Netflix",
22
- "JPM - JPMorgan",
23
- "JNJ - Johnson & Johnson"
24
- ]
25
- self.stock_symbols = ['AAPL', 'MSFT', 'GOOGL', 'AMZN', 'TSLA', 'META', 'NVDA', 'NFLX', 'JPM', 'JNJ']
26
- print("βœ… Fresh Risk Analyzer Ready!")
27
-
28
- def get_stock_data(self, selected_indices, period='2y'):
29
- """Get data for selected stock indices"""
30
- try:
31
- symbols = [self.stock_symbols[i] for i in selected_indices]
32
- print(f"πŸ“Š Fetching data for: {symbols}")
33
-
34
- data = yf.download(symbols, period=period, progress=False)['Adj Close']
35
- if data.empty:
36
- return None, None
37
- return data, symbols
38
- except Exception as e:
39
- print(f"❌ Data fetch error: {str(e)}")
40
- return None, None
41
-
42
- def run_analysis(self, selected_indices, days=252, simulations=5000):
43
- """Run complete risk analysis"""
44
- if not selected_indices:
45
- return None, None, "Please select at least one stock"
46
 
47
- try:
48
- # Get data
49
- data, symbols = self.get_stock_data(selected_indices)
50
- if data is None:
51
- return None, None, "Failed to fetch stock data"
52
-
53
- # Calculate returns
54
- returns = data.pct_change().dropna()
55
- if returns.empty:
56
- return None, None, "Insufficient data for analysis"
57
-
58
- n_stocks = len(symbols)
59
- weights = np.array([1/n_stocks] * n_stocks)
60
-
61
- # Calculate parameters
62
- mean_returns = returns.mean().values
63
- cov_matrix = returns.cov().values
64
-
65
- # Make covariance matrix positive definite
66
- min_eig = np.min(np.real(np.linalg.eigvals(cov_matrix)))
67
- if min_eig < 0:
68
- cov_matrix -= 10 * min_eig * np.eye(*cov_matrix.shape)
69
-
70
- print(f"🎯 Running {simulations} simulations for {symbols}...")
71
-
72
- # Generate simulation
73
- np.random.seed(42)
74
- L = np.linalg.cholesky(cov_matrix)
75
-
76
- simulation_results = []
77
-
78
- for i in range(simulations):
79
- random_numbers = np.random.normal(0, 1, size=(days, n_stocks))
80
- correlated_returns = random_numbers @ L.T + mean_returns
81
-
82
- portfolio_value = 100.0
83
- portfolio_path = [portfolio_value]
84
-
85
- for day in range(days):
86
- daily_return = np.dot(correlated_returns[day], weights)
87
- portfolio_value = portfolio_value * (1 + daily_return)
88
- portfolio_path.append(portfolio_value)
89
-
90
- simulation_results.append(portfolio_path)
91
-
92
- simulation_array = np.array(simulation_results)
93
-
94
- # Calculate metrics
95
- final_values = simulation_array[:, -1]
96
- metrics = {
97
- 'expected_value': float(np.mean(final_values)),
98
- 'prob_10_loss': float(np.mean(final_values < 90)),
99
- 'prob_20_loss': float(np.mean(final_values < 80)),
100
- 'var_95': float(np.percentile(final_values, 5)),
101
- 'best_case': float(np.percentile(final_values, 95)),
102
- 'stocks': symbols,
103
- 'weights': [f"{(1/n_stocks)*100:.1f}%" for _ in range(n_stocks)]
104
- }
105
-
106
- print("βœ… Analysis completed successfully!")
107
- return metrics, simulation_array, None
108
-
109
- except Exception as e:
110
- print(f"❌ Analysis error: {str(e)}")
111
- return None, None, f"Analysis failed: {str(e)}"
112
-
113
- def create_plots(self, metrics, simulations):
114
- """Create all visualization plots"""
115
- if metrics is None or simulations is None:
116
- return None, None, None
117
-
118
- # Simulation plot
119
- sim_fig = go.Figure()
120
- for i in range(min(20, len(simulations))):
121
- sim_fig.add_trace(go.Scatter(
122
- y=simulations[i], mode='lines', line=dict(width=1, color='blue'), opacity=0.1, showlegend=False
123
- ))
124
 
125
- mean_path = np.mean(simulations, axis=0)
126
- sim_fig.add_trace(go.Scatter(y=mean_path, mode='lines', line=dict(width=3, color='red'), name='Average'))
 
 
127
 
128
- stock_label = metrics['stocks'][0] if len(metrics['stocks']) == 1 else f"{len(metrics['stocks'])} Stocks"
129
- sim_fig.update_layout(title=f"Monte Carlo Simulation - {stock_label}", height=400)
130
 
131
- # Distribution plot
132
- final_values = simulations[:, -1]
133
- dist_fig = px.histogram(x=final_values, nbins=50, title="Portfolio Value Distribution")
134
- dist_fig.add_vline(x=metrics['expected_value'], line_dash="dash", line_color="red")
135
- dist_fig.add_vline(x=metrics['var_95'], line_dash="dash", line_color="orange")
136
- dist_fig.update_layout(height=400)
137
 
138
- # Risk gauge
139
- risk_prob = metrics['prob_10_loss'] * 100
140
- gauge_fig = go.Figure(go.Indicator(
141
- mode="gauge+number", value=risk_prob, title={'text': "10% Loss Probability"},
142
- gauge={'axis': {'range': [0, 50]}, 'bar': {'color': "darkblue"},
143
- 'steps': [{'range': [0, 15], 'color': "green"},
144
- {'range': [15, 30], 'color': "yellow"},
145
- {'range': [30, 50], 'color': "red"}]}
146
- ))
147
- gauge_fig.update_layout(height=300)
148
 
149
- return sim_fig, dist_fig, gauge_fig
150
-
151
- def create_summary(self, metrics, days, sims):
152
- """Create summary HTML"""
153
- if metrics is None:
154
- return "No results available"
155
 
156
- risk_level = "LOW" if metrics['prob_10_loss'] < 0.1 else "MEDIUM" if metrics['prob_10_loss'] < 0.2 else "HIGH"
157
- risk_color = "green" if risk_level == "LOW" else "orange" if risk_level == "MEDIUM" else "red"
 
158
 
159
- weights_text = " β€’ ".join([f"{stock}: {weight}" for stock, weight in zip(metrics['stocks'], metrics['weights'])])
 
 
 
160
 
161
- return f"""
162
- <div style="padding: 20px; background: #f0f8ff; border-radius: 10px;">
163
- <h2>πŸ“Š Risk Analysis Report</h2>
164
- <div style="background: white; padding: 15px; border-radius: 8px; margin: 10px 0;">
165
- <h3>Portfolio: {', '.join(metrics['stocks'])}</h3>
166
- <p><strong>Weights:</strong> {weights_text}</p>
167
- <p><strong>Period:</strong> {days} days | <strong>Simulations:</strong> {sims}</p>
168
- </div>
169
-
170
- <div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px;">
171
- <div style="background: white; padding: 10px; border-radius: 5px;">
172
- <h4>Expected Value</h4>
173
- <p style="font-size: 20px; color: blue;">${metrics['expected_value']:.2f}</p>
174
- </div>
175
- <div style="background: white; padding: 10px; border-radius: 5px;">
176
- <h4>Risk Level</h4>
177
- <p style="font-size: 20px; color: {risk_color};">{risk_level}</p>
178
- </div>
179
- <div style="background: white; padding: 10px; border-radius: 5px;">
180
- <h4>10% Loss Chance</h4>
181
- <p style="font-size: 20px; color: orange;">{metrics['prob_10_loss']*100:.1f}%</p>
182
- </div>
183
- <div style="background: white; padding: 10px; border-radius: 5px;">
184
- <h4>Worst Case</h4>
185
- <p style="font-size: 20px; color: red;">${metrics['var_95']:.2f}</p>
186
- </div>
187
- </div>
188
- </div>
189
- """
190
 
191
- # Create app instance
192
- app = FreshRiskApp()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
 
194
- # Build Gradio interface
195
- with gr.Blocks(title="Stock Risk Analyzer") as demo:
196
- gr.Markdown("# πŸ“ˆ Stock Portfolio Risk Analyzer")
197
- gr.Markdown("**Analyze risk for single stocks or portfolios using Monte Carlo simulations**")
 
 
 
 
198
 
199
  with gr.Row():
200
- with gr.Column():
201
- gr.Markdown("### Select Stocks")
202
- stock_checkboxes = gr.CheckboxGroup(
203
- choices=app.stock_list,
204
- label="Choose stocks for analysis",
205
- value=[0, 1, 2] # Default: AAPL, MSFT, GOOGL
 
 
 
 
 
 
 
 
 
 
 
206
  )
207
 
208
- gr.Markdown("### Simulation Settings")
209
- days_slider = gr.Slider(30, 500, 252, label="Time Horizon (Days)")
210
- sims_dropdown = gr.Dropdown([1000, 5000, 10000], value=5000, label="Number of Simulations")
211
-
212
- analyze_btn = gr.Button("πŸš€ Run Analysis", variant="primary")
213
-
214
- with gr.Column():
215
- gr.Markdown("### Analysis Results")
216
- results_html = gr.HTML()
217
 
218
- with gr.Row():
219
- gauge_plot = gr.Plot()
220
- sim_plot = gr.Plot()
 
 
 
 
 
221
 
222
- dist_plot = gr.Plot()
223
-
224
- # Handle analysis
225
- def run_complete_analysis(stock_indices, days, sims):
226
- metrics, simulations, error = app.run_analysis(stock_indices, days, sims)
227
-
228
- if error:
229
- return f"<div style='color: red; padding: 20px;'><h3>❌ Error</h3><p>{error}</p></div>", None, None, None
 
 
 
230
 
231
- summary = app.create_summary(metrics, days, sims)
232
- sim_fig, dist_fig, gauge_fig = app.create_plots(metrics, simulations)
233
-
234
- return summary, gauge_fig, sim_fig, dist_fig
235
-
 
 
 
 
 
 
 
 
 
 
236
  analyze_btn.click(
237
- fn=run_complete_analysis,
238
- inputs=[stock_checkboxes, days_slider, sims_dropdown],
239
- outputs=[results_html, gauge_plot, sim_plot, dist_plot]
 
 
 
 
 
 
 
 
 
 
240
  )
241
 
 
242
  if __name__ == "__main__":
243
- demo.launch(share=True)
 
1
  import gradio as gr
2
  import pandas as pd
3
  import numpy as np
 
 
4
  import yfinance as yf
5
+ import matplotlib.pyplot as plt
6
+ import io
7
+ import base64
8
 
9
+ def analyze_stock(stock_choice, days, simulations):
10
+ """
11
+ Simple stock risk analysis - WORKS 100%
12
+ """
13
+ try:
14
+ # Validate inputs
15
+ if not stock_choice:
16
+ return "❌ Please select a stock", None
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
+ print(f"πŸ”„ Analyzing {stock_choice} for {days} days with {simulations} simulations...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ # Get stock data
21
+ stock_data = yf.download(stock_choice, period="1y", progress=False)
22
+ if stock_data.empty:
23
+ return "❌ Could not fetch stock data. Please try again.", None
24
 
25
+ # Calculate daily returns
26
+ returns = stock_data['Adj Close'].pct_change().dropna()
27
 
28
+ if len(returns) < 10:
29
+ return "❌ Insufficient data for analysis", None
 
 
 
 
30
 
31
+ # Calculate parameters
32
+ mean_return = returns.mean()
33
+ std_return = returns.std()
 
 
 
 
 
 
 
34
 
35
+ # Simple Monte Carlo simulation
36
+ np.random.seed(42)
37
+ daily_returns = np.random.normal(mean_return, std_return, (simulations, days))
 
 
 
38
 
39
+ # Calculate portfolio paths
40
+ portfolio_paths = 100 * (1 + daily_returns).cumprod(axis=1)
41
+ final_values = portfolio_paths[:, -1]
42
 
43
+ # Calculate risk metrics
44
+ expected_value = np.mean(final_values)
45
+ loss_probability = np.mean(final_values < 90) # Probability of losing more than 10%
46
+ worst_case = np.percentile(final_values, 5) # 5% VaR
47
 
48
+ # Create result text
49
+ result_text = f"""
50
+ πŸ“Š **STOCK RISK ANALYSIS REPORT**
51
+
52
+ **Stock:** {stock_choice}
53
+ **Analysis Period:** {days} trading days
54
+ **Simulations:** {simulations:,}
55
+
56
+ **πŸ“ˆ RESULTS:**
57
+ β€’ Expected Value: ${expected_value:.2f}
58
+ β€’ 10% Loss Probability: {loss_probability*100:.1f}%
59
+ β€’ Worst Case (5% VaR): ${worst_case:.2f}
60
+ β€’ Best Case (95%): ${np.percentile(final_values, 95):.2f}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
+ **πŸ“‰ RISK LEVEL:** {'LOW' if loss_probability < 0.2 else 'MEDIUM' if loss_probability < 0.4 else 'HIGH'}
63
+ """
64
+
65
+ # Create simple plot
66
+ plt.figure(figsize=(10, 6))
67
+ plt.hist(final_values, bins=50, alpha=0.7, color='skyblue', edgecolor='black')
68
+ plt.axvline(expected_value, color='red', linestyle='--', label=f'Mean: ${expected_value:.2f}')
69
+ plt.axvline(worst_case, color='orange', linestyle='--', label=f'5% VaR: ${worst_case:.2f}')
70
+ plt.xlabel('Portfolio Value ($)')
71
+ plt.ylabel('Frequency')
72
+ plt.title(f'Distribution of Final Values - {stock_choice}')
73
+ plt.legend()
74
+ plt.grid(True, alpha=0.3)
75
+
76
+ # Save plot to bytes
77
+ buf = io.BytesIO()
78
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
79
+ plt.close()
80
+ buf.seek(0)
81
+
82
+ # Convert to base64 for Gradio
83
+ plot_base64 = base64.b64encode(buf.read()).decode('utf-8')
84
+ plot_html = f'<img src="data:image/png;base64,{plot_base64}" width="100%">'
85
+
86
+ return result_text, plot_html
87
+
88
+ except Exception as e:
89
+ error_msg = f"❌ Error occurred: {str(e)}"
90
+ print(error_msg)
91
+ return error_msg, None
92
 
93
+ # Create Gradio interface
94
+ with gr.Blocks(theme=gr.themes.Soft(), title="Simple Stock Risk Analyzer") as demo:
95
+ gr.Markdown("""
96
+ # πŸ“ˆ Simple Stock Risk Analyzer
97
+ **Analyze stock risk using Monte Carlo simulations**
98
+
99
+ *This app helps you understand the potential risk and returns of individual stocks.*
100
+ """)
101
 
102
  with gr.Row():
103
+ with gr.Column(scale=1):
104
+ gr.Markdown("### πŸ”§ Configuration")
105
+
106
+ stock_dropdown = gr.Dropdown(
107
+ choices=[
108
+ "AAPL - Apple",
109
+ "MSFT - Microsoft",
110
+ "GOOGL - Google",
111
+ "AMZN - Amazon",
112
+ "TSLA - Tesla",
113
+ "META - Meta Platforms",
114
+ "NVDA - NVIDIA",
115
+ "NFLX - Netflix"
116
+ ],
117
+ value="AAPL - Apple",
118
+ label="Select Stock",
119
+ info="Choose one stock to analyze"
120
  )
121
 
122
+ days_slider = gr.Slider(
123
+ minimum=30,
124
+ maximum=365,
125
+ value=252,
126
+ step=30,
127
+ label="Time Horizon (Days)",
128
+ info="252 days = 1 trading year"
129
+ )
 
130
 
131
+ simulations_slider = gr.Slider(
132
+ minimum=1000,
133
+ maximum=10000,
134
+ value=5000,
135
+ step=1000,
136
+ label="Number of Simulations",
137
+ info="More simulations = more accurate results"
138
+ )
139
 
140
+ analyze_btn = gr.Button("πŸš€ Analyze Risk", variant="primary", size="lg")
141
+
142
+ gr.Markdown("""
143
+ ---
144
+ **πŸ’‘ How it works:**
145
+ 1. Select a stock from the dropdown
146
+ 2. Set your time horizon
147
+ 3. Choose number of simulations
148
+ 4. Click "Analyze Risk"
149
+ 5. View your risk report!
150
+ """)
151
 
152
+ with gr.Column(scale=2):
153
+ gr.Markdown("### πŸ“Š Analysis Results")
154
+
155
+ results_output = gr.Textbox(
156
+ label="Risk Analysis Report",
157
+ lines=10,
158
+ max_lines=15,
159
+ show_copy_button=True
160
+ )
161
+
162
+ plot_output = gr.HTML(
163
+ label="Value Distribution Chart"
164
+ )
165
+
166
+ # Set up the analysis function
167
  analyze_btn.click(
168
+ fn=analyze_stock,
169
+ inputs=[stock_dropdown, days_slider, simulations_slider],
170
+ outputs=[results_output, plot_output]
171
+ )
172
+
173
+ # Footer
174
+ gr.Markdown("---")
175
+ gr.Markdown(
176
+ """
177
+ <div style="text-align: center; color: #666;">
178
+ <p>Built with ❀️ using Gradio & Yahoo Finance | Simple Stock Risk Analyzer v1.0</p>
179
+ </div>
180
+ """
181
  )
182
 
183
+ # Launch the app
184
  if __name__ == "__main__":
185
+ demo.launch(share=True, debug=True)