QuantumLearner commited on
Commit
1d8da95
·
verified ·
1 Parent(s): d37ef3c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +137 -73
app.py CHANGED
@@ -4,60 +4,70 @@ import yfinance as yf
4
  import plotly.graph_objects as go
5
  import streamlit as st
6
 
7
- st.set_page_config(page_title = "Analyzing Future Stock Price Movements with Monte Carlo Simulations", layout = "wide")
8
- st.title('Analyzing Future Stock Price Movements with Monte Carlo Simulations')
9
-
10
- # Sidebar inputs
11
- st.sidebar.header('Input Parameters')
12
- ticker = st.sidebar.text_input('Enter Stock Ticker', 'AFX.DE')
13
- start_date = st.sidebar.date_input('Start Date', pd.to_datetime('2020-01-01'))
14
- end_date = st.sidebar.date_input('End Date', pd.to_datetime('2024-12-31'))
15
- days_to_forecast = st.sidebar.slider('Time Horizon (Days)', min_value=1, max_value=60, value=30)
16
- num_simulations = st.sidebar.number_input('Number of Simulations', min_value=100, max_value=100000, value=10000, step=100)
17
- lower_threshold = st.sidebar.number_input('Lower Threshold', min_value=0, max_value=10000, value=90)
18
- upper_threshold = st.sidebar.number_input('Upper Threshold', min_value=0, max_value=10000, value=110)
19
- volatility_bsm = st.sidebar.number_input('BSM Volatility (Annualized)', min_value=0.01, max_value=10.0, value=0.29, step=0.01)
20
-
21
- st.write("""
22
- This analysis estimates potential price movements of a selected stock over a specified time horizon. The estimates are based on historical volatility and the implied volatility derived fromthe Black-Scholes-Merton model. You can adjust the time horizon, number of simulations, and implied volatility measure to explore different scenarios of price dynamics.
23
  """)
24
 
25
- st.markdown("""
26
- ### How to Use This App
27
- 1. **Input Parameters**: Use the sidebar to enter the stock ticker, date range, and other parameters for the analyses.
28
- 2. **Run the Analysis**: Click the "Run" button to perform the analyses and visualize the results.
29
- Each analysis is accompanied by a detailed explanation and visual representation, providing insights into the stock's price behavior and helping traders make informed decisions regarding potential price movements.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  """)
31
 
32
  # Adding LaTeX formatted formulas
33
- # Display the main formula for Monte Carlo simulations with clear, basic LaTeX
34
  st.latex(r'''
35
  P_t = P_0 \times e^{(\mu - \frac{1}{2} \sigma^2) \times t + \sigma \times \sqrt{t} \times Z}
36
  ''')
37
 
38
- # Provide detailed explanations using plain text
39
  st.markdown("""
40
- **Monte Carlo Simulation Explained:**
41
- - **(P_t)**: Estimated stock price at time (t).
42
- - **(P_0)**: Current stock price.
43
- - **(mu)**: Mean of the log returns.
44
- - **(sigma)**: Standard deviation of the log returns, representing historical volatility.
45
  - **(t)**: Time horizon in days.
46
  - **(Z)**: Random variable from the standard normal distribution.
47
- This formula models future stock prices using a stochastic process known as the Monte Carlo simulation. It considers both the average return and the variability in returns to project future price movements. The random component (Z) introduces randomness reflecting the unpredictable nature of stock price movements.
48
- """)
49
-
50
- # Note on usage
51
- st.markdown("""
52
- Use this tool to simulate different scenarios by varying the number of simulations and observing the distribution of possible future prices. Adjust the time horizon and volatility to see how these factors influence the projected price range. This analysis is crucial for assessing potential investment risks and rewards.
53
  """)
54
 
55
  st.write(f"""
56
  ### Monte Carlo Simulations
57
- These simulations project multiple potential future price paths for the stock based on the volatility models described. By running {num_simulations} simulations, the tool generates a distribution of possible future prices, allowing us to calculate confidence intervals and probabilities for various price levels.
 
58
  """)
59
 
60
- if st.sidebar.button('Run'):
 
61
  stock_data = yf.download(ticker, start=start_date, end=end_date)
62
 
63
  if not stock_data.empty:
@@ -79,74 +89,128 @@ if st.sidebar.button('Run'):
79
  simulated_prices[t] = simulated_prices[t - 1] * np.exp(random_walk)
80
  return simulated_prices
81
 
 
 
82
  simulated_prices_historical = run_simulation(log_returns.std(), 1)
83
- simulated_prices_bsm = run_simulation(volatility_bsm, 1, annualized=True)
84
 
85
  fig1 = go.Figure()
86
- fig2 = go.Figure()
87
 
88
- for simulated_prices, fig, title in zip([simulated_prices_historical, simulated_prices_bsm],
89
- [fig1, fig2], ['Historical Volatility', 'BSM Volatility']):
90
- mean_price_path = np.mean(simulated_prices, axis=1)
91
- median_price_path = np.median(simulated_prices, axis=1)
92
- lower_bound_68 = np.percentile(simulated_prices, 16, axis=1)
93
- upper_bound_68 = np.percentile(simulated_prices, 84, axis=1)
94
- lower_bound_95 = np.percentile(simulated_prices, 2.5, axis=1)
95
- upper_bound_95 = np.percentile(simulated_prices, 97.5, axis=1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
96
 
97
  for i in range(min(num_simulations, 100)): # Plot a subset of paths for clarity
98
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=simulated_prices[:, i], mode='lines', line=dict(color='lightgray', width=0.5), opacity=0.3, showlegend=False))
99
 
100
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=mean_price_path, mode='lines', name='Mean Price Path', line=dict(color='black')))
101
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=median_price_path, mode='lines', name='Median Price Path', line=dict(color='blue')))
102
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_68, mode='lines', name='68% confidence interval (Lower)', line=dict(color='green', dash='dash')))
103
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_68, mode='lines', name='68% confidence interval (Upper)', line=dict(color='green', dash='dash')))
104
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_95, mode='lines', name='95% confidence interval (Lower)', line=dict(color='blue', dash='dash')))
105
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_95, mode='lines', name='95% confidence interval (Upper)', line=dict(color='red', dash='dash')))
106
 
107
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[upper_threshold] * days_to_forecast, mode='lines', name='Upper Threshold', line=dict(color='purple')))
108
- fig.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[lower_threshold] * days_to_forecast, mode='lines', name='Lower Threshold', line=dict(color='orange')))
109
 
110
- above_upper_threshold_prob = (simulated_prices[-1] > upper_threshold).sum() / num_simulations
111
- below_lower_threshold_prob = (simulated_prices[-1] < lower_threshold).sum() / num_simulations
112
  between_thresholds_prob = 1 - above_upper_threshold_prob - below_lower_threshold_prob
113
 
114
- fig.update_layout(
115
- title=f'Monte Carlo Confidence Cone for {ticker} using {title}',
116
  xaxis_title='Days',
117
- yaxis_title='Stock Price',
118
  legend_title='Legend'
119
  )
120
-
121
-
122
- fig.add_annotation(text=f'P(>{upper_threshold:.2f}): {above_upper_threshold_prob:.2%}<br>'
123
  f'P(<{lower_threshold:.2f}): {below_lower_threshold_prob:.2%}<br>'
124
  f'P({lower_threshold:.2f} - {upper_threshold:.2f}): {between_thresholds_prob:.2%}',
125
- xref='paper', yref='paper', x=0.02, y=0.95, showarrow=False, bordercolor="black", borderwidth=1)
 
 
126
 
127
- # Add elaboration text below each graph
128
- st.plotly_chart(fig)
129
  st.markdown(f"""
130
  <h4 style='font-size: 16px;'>Interpretation of Results</h4>
131
  <ul style='font-size: 14px;'>
132
- <li><strong>Mean Price Path:</strong> The average simulated stock price path over the forecast period.</li>
133
- <li><strong>Median Price Path:</strong> The median simulated stock price path over the forecast period.</li>
134
- <li><strong>68% Confidence Interval:</strong> The range within which 68% of the simulated stock prices fall.</li>
135
- <li><strong>95% Confidence Interval:</strong> The range within which 95% of the simulated stock prices fall.</li>
136
  <li><strong>Probability of Exceeding Upper Threshold ({upper_threshold}):</strong> {above_upper_threshold_prob:.2%}</li>
137
  <li><strong>Probability of Falling Below Lower Threshold ({lower_threshold}):</strong> {below_lower_threshold_prob:.2%}</li>
138
  <li><strong>Probability of Staying Between Thresholds ({lower_threshold} - {upper_threshold}):</strong> {between_thresholds_prob:.2%}</li>
139
  </ul>
140
  """, unsafe_allow_html=True)
141
-
142
  else:
143
  st.write("No data found for the given ticker and date range.")
144
 
145
-
146
  hide_streamlit_style = """
147
  <style>
148
  #MainMenu {visibility: hidden;}
149
  footer {visibility: hidden;}
150
  </style>
151
  """
152
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
4
  import plotly.graph_objects as go
5
  import streamlit as st
6
 
7
+ # Set up the Streamlit app configuration
8
+ st.set_page_config(page_title="Analyzing Future Price Movements with Monte Carlo Simulations", layout="wide")
9
+ st.title('Analyzing Future Price Movements with Monte Carlo Simulations')
10
+
11
+ # Sidebar instructions
12
+ st.sidebar.title('Input Parameters')
13
+ st.sidebar.subheader('How to Use This App')
14
+ st.sidebar.markdown("""
15
+ 1. **Enter Ticker and Date**: Type the stock or cryptocurrency ticker and select the date range.
16
+ 2. **Set Parameters**: Adjust the time horizon, number of simulations, and other parameters to customize the analysis.
17
+ - **For Cryptocurrencies**: The BSM analysis is not applicable. Set the BSM volatility to 0 to exclude the BSM-based analysis.
 
 
 
 
 
18
  """)
19
 
20
+ # Wrapping ticker and date settings in an expander
21
+ with st.sidebar.expander("Ticker and Date Settings", expanded=True):
22
+ ticker = st.text_input('Enter Stock/Crypto Ticker', 'AFX.DE', help="Enter the ticker symbol of the stock or cryptocurrency pair you want to analyze (e.g., 'AAPL' for Apple, 'BTC-USD' for Bitcoin).")
23
+ start_date = st.date_input('Start Date', pd.to_datetime('2020-01-01'), help="Select the start date for fetching historical data.")
24
+ end_date = st.date_input('End Date', pd.to_datetime('today') + pd.DateOffset(1), help="Select the end date for fetching historical data (default is today plus one day).")
25
+
26
+ # Wrapping parameter settings in an expander
27
+ with st.sidebar.expander("Parameter Settings", expanded=True):
28
+ days_to_forecast = st.slider('Time Horizon (Days)', min_value=1, max_value=60, value=30, help="Select the number of days into the future for the simulation.")
29
+ num_simulations = st.number_input('Number of Simulations', min_value=100, max_value=100000, value=10000, step=100, help="Set the number of Monte Carlo simulations to run.")
30
+ lower_threshold = st.number_input('Lower Threshold', min_value=0, max_value=10000, value=50, help="Set the lower price threshold for probability calculation.")
31
+ upper_threshold = st.number_input('Upper Threshold', min_value=0, max_value=10000, value=70, help="Set the upper price threshold for probability calculation.")
32
+ volatility_bsm = st.number_input('BSM Volatility (Annualized)', min_value=0.0, max_value=10.0, value=0.29, step=0.01, help="Set the annualized volatility for the Black-Scholes-Merton model. Set to 0 if analyzing a cryptocurrency.")
33
+
34
+ # Detect if the asset is a cryptocurrency
35
+ is_crypto = '-' in ticker
36
+
37
+ # Automatically set BSM volatility to 0 if it's a cryptocurrency
38
+ if is_crypto:
39
+ volatility_bsm = 0.0
40
+
41
+ # Description of the analysis
42
+ st.write("""
43
+ This tool estimates potential price movements of a selected stock or cryptocurrency over a specified time horizon using Monte Carlo Simulations.
44
+ The estimates are based on historical volatility and the implied volatility derived from the Black-Scholes-Merton model.
45
+ You can adjust the time horizon, number of simulations, and volatility measures to explore different scenarios of price dynamics.
46
  """)
47
 
48
  # Adding LaTeX formatted formulas
 
49
  st.latex(r'''
50
  P_t = P_0 \times e^{(\mu - \frac{1}{2} \sigma^2) \times t + \sigma \times \sqrt{t} \times Z}
51
  ''')
52
 
 
53
  st.markdown("""
54
+ **Monte Carlo Simulation Inputs:**
55
+ - **(Pt)**: Estimated asset price at time (t).
56
+ - **(P0)**: Current asset price.
57
+ - **(μ)**: Mean of the log returns.
58
+ - **(σ)**: Standard deviation of the log returns, representing historical volatility.
59
  - **(t)**: Time horizon in days.
60
  - **(Z)**: Random variable from the standard normal distribution.
 
 
 
 
 
 
61
  """)
62
 
63
  st.write(f"""
64
  ### Monte Carlo Simulations
65
+ These simulations project multiple potential future price paths for the asset based on the volatility models described.
66
+ By running {num_simulations} simulations, the tool generates a distribution of possible future prices. This allows us to calculate confidence intervals and probabilities for various price levels.
67
  """)
68
 
69
+ # Running the analysis when the button is pressed
70
+ if st.sidebar.button('Run Analysis'):
71
  stock_data = yf.download(ticker, start=start_date, end=end_date)
72
 
73
  if not stock_data.empty:
 
89
  simulated_prices[t] = simulated_prices[t - 1] * np.exp(random_walk)
90
  return simulated_prices
91
 
92
+ # Run simulations based on historical volatility
93
+ st.write(f"### Simulation with Historical Volatility for {ticker}")
94
  simulated_prices_historical = run_simulation(log_returns.std(), 1)
 
95
 
96
  fig1 = go.Figure()
 
97
 
98
+ mean_price_path = np.mean(simulated_prices_historical, axis=1)
99
+ median_price_path = np.median(simulated_prices_historical, axis=1)
100
+ lower_bound_68 = np.percentile(simulated_prices_historical, 16, axis=1)
101
+ upper_bound_68 = np.percentile(simulated_prices_historical, 84, axis=1)
102
+ lower_bound_95 = np.percentile(simulated_prices_historical, 2.5, axis=1)
103
+ upper_bound_95 = np.percentile(simulated_prices_historical, 97.5, axis=1)
104
+
105
+ for i in range(min(num_simulations, 100)): # Plot a subset of paths for clarity
106
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=simulated_prices_historical[:, i], mode='lines', line=dict(color='lightgray', width=0.5), opacity=0.3, showlegend=False))
107
+
108
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=mean_price_path, mode='lines', name='Mean Price Path', line=dict(color='black')))
109
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=median_price_path, mode='lines', name='Median Price Path', line=dict(color='blue')))
110
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_68, mode='lines', name='68% confidence interval (Lower)', line=dict(color='green', dash='dash')))
111
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_68, mode='lines', name='68% confidence interval (Upper)', line=dict(color='green', dash='dash')))
112
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_95, mode='lines', name='95% confidence interval (Lower)', line=dict(color='blue', dash='dash')))
113
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_95, mode='lines', name='95% confidence interval (Upper)', line=dict(color='red', dash='dash')))
114
+
115
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[upper_threshold] * days_to_forecast, mode='lines', name='Upper Threshold', line=dict(color='purple')))
116
+ fig1.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[lower_threshold] * days_to_forecast, mode='lines', name='Lower Threshold', line=dict(color='orange')))
117
+
118
+ above_upper_threshold_prob = (simulated_prices_historical[-1] > upper_threshold).sum() / num_simulations
119
+ below_lower_threshold_prob = (simulated_prices_historical[-1] < lower_threshold).sum() / num_simulations
120
+ between_thresholds_prob = 1 - above_upper_threshold_prob - below_lower_threshold_prob
121
+
122
+ fig1.update_layout(
123
+ title=f'Monte Carlo Confidence Cone for {ticker} using Historical Volatility',
124
+ xaxis_title='Days',
125
+ yaxis_title='Price',
126
+ legend_title='Legend'
127
+ )
128
+
129
+ fig1.add_annotation(text=f'P(>{upper_threshold:.2f}): {above_upper_threshold_prob:.2%}<br>'
130
+ f'P(<{lower_threshold:.2f}): {below_lower_threshold_prob:.2%}<br>'
131
+ f'P({lower_threshold:.2f} - {upper_threshold:.2f}): {between_thresholds_prob:.2%}',
132
+ xref='paper', yref='paper', x=0.02, y=0.95, showarrow=False, bordercolor="black", borderwidth=1)
133
+
134
+ st.plotly_chart(fig1)
135
+
136
+ st.markdown(f"""
137
+ <h4 style='font-size: 16px;'>Interpretation of Results</h4>
138
+ <ul style='font-size: 14px;'>
139
+ <li><strong>Mean Price Path:</strong> The average simulated price path over the forecast period.</li>
140
+ <li><strong>Median Price Path:</strong> The median simulated price path over the forecast period.</li>
141
+ <li><strong>68% Confidence Interval:</strong> The range within which 68% of the simulated prices fall.</li>
142
+ <li><strong>95% Confidence Interval:</strong> The range within which 95% of the simulated prices fall.</li>
143
+ <li><strong>Probability of Exceeding Upper Threshold ({upper_threshold}):</strong> {above_upper_threshold_prob:.2%}</li>
144
+ <li><strong>Probability of Falling Below Lower Threshold ({lower_threshold}):</strong> {below_lower_threshold_prob:.2%}</li>
145
+ <li><strong>Probability of Staying Between Thresholds ({lower_threshold} - {upper_threshold}):</strong> {between_thresholds_prob:.2%}</li>
146
+ </ul>
147
+ """, unsafe_allow_html=True)
148
+
149
+ # Run BSM-based simulation only if volatility_bsm is greater than 0
150
+ if volatility_bsm > 0:
151
+ st.write(f"### Simulation with BSM Volatility for {ticker}")
152
+ simulated_prices_bsm = run_simulation(volatility_bsm, 1, annualized=True)
153
+
154
+ fig2 = go.Figure()
155
+
156
+ mean_price_path = np.mean(simulated_prices_bsm, axis=1)
157
+ median_price_path = np.median(simulated_prices_bsm, axis=1)
158
+ lower_bound_68 = np.percentile(simulated_prices_bsm, 16, axis=1)
159
+ upper_bound_68 = np.percentile(simulated_prices_bsm, 84, axis=1)
160
+ lower_bound_95 = np.percentile(simulated_prices_bsm, 2.5, axis=1)
161
+ upper_bound_95 = np.percentile(simulated_prices_bsm, 97.5, axis=1)
162
 
163
  for i in range(min(num_simulations, 100)): # Plot a subset of paths for clarity
164
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=simulated_prices_bsm[:, i], mode='lines', line=dict(color='lightgray', width=0.5), opacity=0.3, showlegend=False))
165
 
166
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=mean_price_path, mode='lines', name='Mean Price Path', line=dict(color='black')))
167
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=median_price_path, mode='lines', name='Median Price Path', line=dict(color='blue')))
168
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_68, mode='lines', name='68% confidence interval (Lower)', line=dict(color='green', dash='dash')))
169
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_68, mode='lines', name='68% confidence interval (Upper)', line=dict(color='green', dash='dash')))
170
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=lower_bound_95, mode='lines', name='95% confidence interval (Lower)', line=dict(color='blue', dash='dash')))
171
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=upper_bound_95, mode='lines', name='95% confidence interval (Upper)', line=dict(color='red', dash='dash')))
172
 
173
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[upper_threshold] * days_to_forecast, mode='lines', name='Upper Threshold', line=dict(color='purple')))
174
+ fig2.add_trace(go.Scatter(x=np.arange(days_to_forecast), y=[lower_threshold] * days_to_forecast, mode='lines', name='Lower Threshold', line=dict(color='orange')))
175
 
176
+ above_upper_threshold_prob = (simulated_prices_bsm[-1] > upper_threshold).sum() / num_simulations
177
+ below_lower_threshold_prob = (simulated_prices_bsm[-1] < lower_threshold).sum() / num_simulations
178
  between_thresholds_prob = 1 - above_upper_threshold_prob - below_lower_threshold_prob
179
 
180
+ fig2.update_layout(
181
+ title=f'Monte Carlo Confidence Cone for {ticker} using BSM Volatility',
182
  xaxis_title='Days',
183
+ yaxis_title='Price',
184
  legend_title='Legend'
185
  )
186
+
187
+ fig2.add_annotation(text=f'P(>{upper_threshold:.2f}): {above_upper_threshold_prob:.2%}<br>'
 
188
  f'P(<{lower_threshold:.2f}): {below_lower_threshold_prob:.2%}<br>'
189
  f'P({lower_threshold:.2f} - {upper_threshold:.2f}): {between_thresholds_prob:.2%}',
190
+ xref='paper', yref='paper', x=0.02, y=0.95, showarrow=False, bordercolor="black", borderwidth=1)
191
+
192
+ st.plotly_chart(fig2)
193
 
 
 
194
  st.markdown(f"""
195
  <h4 style='font-size: 16px;'>Interpretation of Results</h4>
196
  <ul style='font-size: 14px;'>
197
+ <li><strong>Mean Price Path:</strong> The average simulated price path over the forecast period.</li>
198
+ <li><strong>Median Price Path:</strong> The median simulated price path over the forecast period.</li>
199
+ <li><strong>68% Confidence Interval:</strong> The range within which 68% of the simulated prices fall.</li>
200
+ <li><strong>95% Confidence Interval:</strong> The range within which 95% of the simulated prices fall.</li>
201
  <li><strong>Probability of Exceeding Upper Threshold ({upper_threshold}):</strong> {above_upper_threshold_prob:.2%}</li>
202
  <li><strong>Probability of Falling Below Lower Threshold ({lower_threshold}):</strong> {below_lower_threshold_prob:.2%}</li>
203
  <li><strong>Probability of Staying Between Thresholds ({lower_threshold} - {upper_threshold}):</strong> {between_thresholds_prob:.2%}</li>
204
  </ul>
205
  """, unsafe_allow_html=True)
 
206
  else:
207
  st.write("No data found for the given ticker and date range.")
208
 
209
+ # Hide the Streamlit main menu and footer for a cleaner interface
210
  hide_streamlit_style = """
211
  <style>
212
  #MainMenu {visibility: hidden;}
213
  footer {visibility: hidden;}
214
  </style>
215
  """
216
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)