QuantumLearner commited on
Commit
cd972cc
·
verified ·
1 Parent(s): 6f75e9d

Create app.py

Browse files
Files changed (1) hide show
  1. app.py +178 -0
app.py ADDED
@@ -0,0 +1,178 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import yfinance as yf
2
+ import numpy as np
3
+ import pandas as pd
4
+ import streamlit as st
5
+ import plotly.graph_objects as go
6
+
7
+ # Fetch stock data
8
+ def get_stock_data(ticker, start_date, end_date):
9
+ stock_data = yf.download(ticker, start=start_date, end=end_date)
10
+ return stock_data['Close']
11
+
12
+ # Bootstrapping simulation function
13
+ def bootstrap_simulation(data, days, n_iterations=10000):
14
+ daily_returns = data.pct_change().dropna()
15
+ simulations = np.zeros((n_iterations, days))
16
+
17
+ for i in range(n_iterations):
18
+ sample = np.random.choice(daily_returns, size=days, replace=True)
19
+ simulations[i] = np.cumprod(1 + sample) * data.iloc[-1]
20
+
21
+ return simulations
22
+
23
+ # Calculate probabilities
24
+ def calculate_probabilities(simulations, thresholds):
25
+ final_prices = simulations[:, -1]
26
+ below = np.mean(final_prices < thresholds[0])
27
+ above = np.mean(final_prices > thresholds[1])
28
+ between = np.mean((final_prices >= thresholds[0]) & (final_prices <= thresholds[1]))
29
+
30
+ return {'below': below, 'between': between, 'above': above}
31
+
32
+ # Calculate percentiles
33
+ def calculate_percentiles(simulations):
34
+ percentiles = np.percentile(simulations, [2.5, 16, 50, 84, 97.5], axis=0)
35
+ return percentiles
36
+
37
+ # Plot distributions
38
+ def plot_distributions(bootstrap_simulations, data, thresholds, bootstrap_probabilities):
39
+ final_bootstrap_prices = bootstrap_simulations[:, -1]
40
+
41
+ mean_bootstrap_price = np.mean(final_bootstrap_prices)
42
+ median_bootstrap_price = np.median(final_bootstrap_prices)
43
+ ci_68_bootstrap = np.percentile(final_bootstrap_prices, [16, 84])
44
+ ci_95_bootstrap = np.percentile(final_bootstrap_prices, [2.5, 97.5])
45
+ latest_price = data.iloc[-1]
46
+
47
+ fig = go.Figure()
48
+
49
+ # Plot for Bootstrapping
50
+ fig.add_trace(go.Histogram(x=final_bootstrap_prices, nbinsx=50, name='Simulated Final Prices',
51
+ marker_color='blue', opacity=0.7))
52
+ fig.add_vline(x=mean_bootstrap_price, line=dict(color='red', dash='dash'), name=f'Mean: {mean_bootstrap_price:.2f}')
53
+ fig.add_vline(x=median_bootstrap_price, line=dict(color='orange', dash='dash'), name=f'Median: {median_bootstrap_price:.2f}')
54
+ fig.add_vline(x=latest_price, line=dict(color='green', dash='dash'), name=f'Latest Price: {latest_price:.2f}')
55
+ fig.add_vrect(x0=ci_68_bootstrap[0], x1=ci_68_bootstrap[1], fillcolor='yellow', opacity=0.2, layer="below", line_width=0, annotation_text="68% CI", annotation_position="top left")
56
+ fig.add_vrect(x0=ci_95_bootstrap[0], x1=ci_95_bootstrap[1], fillcolor='grey', opacity=0.2, layer="below", line_width=0, annotation_text="95% CI", annotation_position="top left")
57
+
58
+ max_freq = np.histogram(final_bootstrap_prices, bins=50)[0].max()
59
+
60
+ # Calculate positions based on a fraction of the max frequency
61
+ mean_y_pos = max_freq * 0.9
62
+ median_y_pos = max_freq * 0.7
63
+ latest_y_pos = max_freq * 0.5
64
+
65
+ # Annotations for the vertical lines
66
+ fig.add_annotation(x=mean_bootstrap_price, y=mean_y_pos, text=f'Mean: {mean_bootstrap_price:.2f}', showarrow=False)
67
+ fig.add_annotation(x=median_bootstrap_price, y=median_y_pos, text=f'Median: {median_bootstrap_price:.2f}', showarrow=False)
68
+ fig.add_annotation(x=latest_price, y=latest_y_pos, text=f'Latest: {latest_price:.2f}', showarrow=False)
69
+
70
+ textstr = f'P(>{thresholds[1]:.2f}): {bootstrap_probabilities["above"]:.2%}<br>' + \
71
+ f'P(<{thresholds[0]:.2f}): {bootstrap_probabilities["below"]:.2%}<br>' + \
72
+ f'P({thresholds[0]:.2f} - {thresholds[1]:.2f}): {bootstrap_probabilities["between"]:.2%}'
73
+ fig.add_annotation(xref='paper', yref='paper', x=0.98, y=0.02, text=textstr, showarrow=False,
74
+ bordercolor="black", borderwidth=1, borderpad=4, bgcolor="white", opacity=0.8)
75
+
76
+ fig.update_layout(title='Bootstrapping Simulation', xaxis_title='Final Price', yaxis_title='Frequency', showlegend=True)
77
+ return fig, mean_bootstrap_price, median_bootstrap_price, ci_68_bootstrap, ci_95_bootstrap, latest_price
78
+
79
+ # Plot price data with simulation cones
80
+ def plot_price_with_cones(data, bootstrap_percentiles, days, thresholds, bootstrap_probabilities):
81
+ last_date = data.index[-1]
82
+ future_dates = pd.date_range(start=last_date + pd.Timedelta(days=1), periods=days, freq='D')
83
+
84
+ fig = go.Figure()
85
+
86
+ # Plot historical prices
87
+ fig.add_trace(go.Scatter(x=data.index, y=data, mode='lines', name='Historical Prices', line=dict(color='black')))
88
+
89
+ # Plot bootstrapping simulation cone
90
+ fig.add_trace(go.Scatter(x=future_dates, y=bootstrap_percentiles[2], mode='lines', name='Bootstrap Median', line=dict(color='red', dash='dash')))
91
+ fig.add_trace(go.Scatter(x=future_dates, y=bootstrap_percentiles[0], fill=None, mode='lines', line=dict(color='lightgrey'), showlegend=False))
92
+ fig.add_trace(go.Scatter(x=future_dates, y=bootstrap_percentiles[4], fill='tonexty', mode='lines', line=dict(color='lightgrey'), name='Bootstrap 95% CI'))
93
+ fig.add_trace(go.Scatter(x=future_dates, y=bootstrap_percentiles[1], fill=None, mode='lines', line=dict(color='lightyellow'), showlegend=False))
94
+ fig.add_trace(go.Scatter(x=future_dates, y=bootstrap_percentiles[3], fill='tonexty', mode='lines', line=dict(color='lightyellow'), name='Bootstrap 68% CI'))
95
+
96
+ # Annotate the thresholds
97
+ fig.add_hline(y=thresholds[0], line=dict(color='blue', dash='dash'), annotation_text=f'Threshold 1: {thresholds[0]}', annotation_position="top left")
98
+ fig.add_hline(y=thresholds[1], line=dict(color='green', dash='dash'), annotation_text=f'Threshold 2: {thresholds[1]}', annotation_position="top left")
99
+
100
+ # Add probability annotations
101
+ textstr_bootstrap = f'Bootstrap Probabilities:<br>Below {thresholds[0]}: {bootstrap_probabilities["below"]:.2%}<br>' + \
102
+ f'Between {thresholds[0]} and {thresholds[1]}: {bootstrap_probabilities["between"]:.2%}<br>' + \
103
+ f'Above {thresholds[1]}: {bootstrap_probabilities["above"]:.2%}'
104
+ fig.add_annotation(xref='paper', yref='paper', x=0.98, y=0.02, text=textstr_bootstrap, showarrow=False,
105
+ bordercolor="black", borderwidth=1, borderpad=4, bgcolor="white", opacity=0.8)
106
+
107
+ fig.update_layout(title='Bootstrapping Simulation Cone', xaxis_title='Date', yaxis_title='Price', showlegend=True)
108
+ fig.update_xaxes(type='date')
109
+
110
+ return fig
111
+
112
+ # Streamlit app
113
+ st.title('Stock Price Simulation')
114
+
115
+ st.sidebar.header('Input Parameters')
116
+
117
+ st.write("""
118
+ ### Description
119
+ This application simulates future stock prices using bootstrapping simulation methods.
120
+ You can specify the stock ticker, the date range, the number of simulation days, the number of simulations, and price thresholds.
121
+ The simulation results will show the probability of the stock price falling below, between, or above the specified thresholds.
122
+
123
+ **How to use:**
124
+ 1. Enter the stock ticker, start date, and end date.
125
+ 2. Set the number of days for the simulation and the number of iterations.
126
+ 3. Enter the price thresholds.
127
+ 4. Click 'Run Simulation' to start the bootstrapping simulation.
128
+
129
+ **Results:**
130
+ The app will display two charts:
131
+ 1. The distribution of the final simulated prices with key statistical measures.
132
+ 2. The historical stock prices with simulated future price cones and the specified thresholds.
133
+ """)
134
+
135
+ ticker = st.sidebar.text_input('Enter Stock Ticker', 'ASML.AS')
136
+ start_date = st.sidebar.date_input('Start Date', pd.to_datetime('2020-01-01'))
137
+ end_date = st.sidebar.date_input('End Date', pd.to_datetime('2025-01-01'))
138
+ days = st.sidebar.number_input('Number of Days for Simulation', min_value=1, max_value=365, value=30)
139
+ n_iterations = st.sidebar.number_input('Number of Simulations', min_value=100, max_value=100000, value=10000)
140
+ threshold1 = st.sidebar.number_input('Threshold 1', min_value=0, value=850)
141
+ threshold2 = st.sidebar.number_input('Threshold 2', min_value=0, value=1000)
142
+ thresholds = [threshold1, threshold2]
143
+
144
+ if st.sidebar.button('Run Simulation'):
145
+ data = get_stock_data(ticker, start_date, end_date)
146
+
147
+ bootstrap_simulations = bootstrap_simulation(data, days, n_iterations)
148
+
149
+ bootstrap_probabilities = calculate_probabilities(bootstrap_simulations, thresholds)
150
+
151
+ bootstrap_percentiles = calculate_percentiles(bootstrap_simulations)
152
+
153
+ fig1, mean_bootstrap_price, median_bootstrap_price, ci_68_bootstrap, ci_95_bootstrap, latest_price = plot_distributions(bootstrap_simulations, data, thresholds, bootstrap_probabilities)
154
+ fig2 = plot_price_with_cones(data, bootstrap_percentiles, days, thresholds, bootstrap_probabilities)
155
+
156
+ st.plotly_chart(fig1)
157
+ st.plotly_chart(fig2)
158
+
159
+ st.write(f"""
160
+ ### Interpretation of Results
161
+
162
+ **Distribution of Final Simulated Prices:**
163
+ - **Mean Final Price:** {mean_bootstrap_price:.2f}
164
+ - **Median Final Price:** {median_bootstrap_price:.2f}
165
+ - **68% Confidence Interval (CI):** [{ci_68_bootstrap[0]:.2f}, {ci_68_bootstrap[1]:.2f}]
166
+ - **95% Confidence Interval (CI):** [{ci_95_bootstrap[0]:.2f}, {ci_95_bootstrap[1]:.2f}]
167
+ - **Latest Price:** {latest_price:.2f}
168
+
169
+ **Bootstrapping Simulation Cone:**
170
+ - **Bootstrap Median:** The median of the simulated future prices for each day.
171
+ - **Bootstrap 68% CI:** The 68% confidence interval for the simulated future prices.
172
+ - **Bootstrap 95% CI:** The 95% confidence interval for the simulated future prices.
173
+ - **Threshold 1 and Threshold 2:** {threshold1:.2f}, {threshold2:.2f}
174
+ - **Probability Annotations:**
175
+ - The probability of the stock price being below Threshold 1: {bootstrap_probabilities["below"]:.2%}
176
+ - The probability of the stock price being between Threshold 1 and Threshold 2: {bootstrap_probabilities["between"]:.2%}
177
+ - The probability of the stock price being above Threshold 2: {bootstrap_probabilities["above"]:.2%}
178
+ """)