QuantumLearner commited on
Commit
88a0c19
·
verified ·
1 Parent(s): 3679932

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +240 -270
app.py CHANGED
@@ -8,7 +8,8 @@ from scipy.signal import argrelextrema
8
  from sklearn.cluster import KMeans
9
  import matplotlib.pyplot as plt
10
 
11
- # Streamlit app setup
 
12
  st.set_page_config(page_title="Identifying Key Support and Resistance In Price Levels", layout="wide")
13
  st.title('Key Support and Resistance In Price Levels')
14
 
@@ -23,53 +24,37 @@ This tool aims to identify key support and resistance price levels in stocks usi
23
  7. **KMeans Clustering**: A machine learning algorithm used to partition the dataset into clusters, identifying patterns and grouping similar price movements together to highlight significant price levels.
24
  """)
25
 
26
- # Initialize session state for data persistence
27
- if 'data' not in st.session_state:
28
- st.session_state.data = None
29
- if 'results' not in st.session_state:
30
- st.session_state.results = {}
31
-
32
- # Sidebar for input parameters
33
  st.sidebar.title('Input Parameters')
34
 
35
- with st.sidebar:
36
- st.header("How to use:")
37
- st.markdown("""
38
- 1. **Enter Ticker**: Specify a stock ticker or crypto pair.
39
- 2. **Set Dates**: Choose the date range for analysis.
40
- 3. **Adjust Parameters**: Modify methodology parameters as needed.
41
- 4. **Select Analysis**: Choose the analysis type to display results.
42
- """)
43
-
44
- # Expander for ticker and date settings
45
- with st.expander("Ticker and Date Settings", expanded=True):
46
- ticker = st.text_input('Stock Ticker or Crypto Pair', 'AAPL', help="Enter stock ticker (e.g., AAPL) or crypto pair (e.g., BTC-USD).")
47
- start_date = st.date_input('Start Date', pd.to_datetime('2023-01-01'))
48
- end_date = st.date_input('End Date', datetime.now() + timedelta(days=1))
49
-
50
- # Expander for methodology-specific parameters
51
- with st.expander("Pivot Points and Levels", expanded=True):
52
- window_period = st.slider('Window Period for Pivot Points and Levels', min_value=10, max_value=60, value=30, help="Set the window period for calculating pivot points and support/resistance levels.")
53
-
54
- with st.expander("Trendlines and Fibonacci Levels", expanded=True):
55
- lookback_period = st.slider('Lookback Period for Trendlines and Fibonacci', min_value=10, max_value=60, value=30, help="Set the lookback period for calculating trendlines and Fibonacci retracement levels.")
56
-
57
- with st.expander("Volume Profile and KMeans", expanded=True):
58
- n_days = st.slider('Lookback Period for Volume Profile and KMeans (Days)', min_value=30, max_value=365, value=60, help="Set the number of days for calculating volume profile and KMeans clustering.")
59
- num_clusters = st.slider('Number of Clusters for KMeans', min_value=2, max_value=10, value=3, help="Set the number of clusters for KMeans analysis.")
60
-
61
- # Select the page (analysis type)
62
- analysis_type = st.radio("Select Analysis", ["Pivot Points", "Support and Resistance", "Swing Highs and Lows", "Fibonacci Retracement Levels", "Trendlines", "Volume Profile", "KMeans Clustering"])
63
-
64
- # Function to fetch and cache data
65
- @st.cache_data(show_spinner=False)
66
- def get_data(ticker, start_date, end_date):
67
- data = yf.download(ticker, start=start_date, end=end_date)
68
- if data.empty:
69
- st.error("No data found for the given ticker and date range.")
70
- return data
71
 
72
- # Functions for different analyses
 
 
 
 
 
 
 
73
  def calculate_pivot_points(df, window):
74
  df['Pivot'] = df['Close'].rolling(window=window).mean()
75
  df['R1'] = 2 * df['Pivot'] - df['Low'].rolling(window=window).min()
@@ -117,241 +102,226 @@ def calculate_kmeans_clusters(data, n_days, num_clusters):
117
  cluster_centers = kmeans.cluster_centers_[:, 1] * (np.max(filtered_data['Close']) - np.min(filtered_data['Close'])) + np.min(filtered_data['Close'])
118
  return cluster_centers
119
 
120
- # Cache results based on analysis type
121
- def cache_results_in_session(data, analysis_type, window_period, lookback_period, n_days, num_clusters):
122
- if analysis_type not in st.session_state.results:
123
- st.session_state.results[analysis_type] = {}
124
 
125
- if analysis_type == "Pivot Points" and 'result' not in st.session_state.results[analysis_type]:
126
- st.session_state.results[analysis_type]['result'] = calculate_pivot_points(data.copy(), window_period)
127
- elif analysis_type == "Support and Resistance" and 'result' not in st.session_state.results[analysis_type]:
 
 
 
128
  support, resistance = find_levels(data.copy(), window_period)
129
  breaks_above_resistance, breaks_below_support = check_significant_break(data.copy(), support, resistance)
130
- st.session_state.results[analysis_type]['result'] = (support, resistance, breaks_above_resistance, breaks_below_support)
131
- elif analysis_type == "Swing Highs and Lows" and 'result' not in st.session_state.results[analysis_type]:
132
- st.session_state.results[analysis_type]['result'] = prepare_data_for_trendlines(data.copy(), lookback_period)
133
- elif analysis_type == "Fibonacci Retracement Levels" and 'result' not in st.session_state.results[analysis_type]:
134
- st.session_state.results[analysis_type]['result'] = calculate_fibonacci_levels(data.copy(), lookback_period)
135
- elif analysis_type == "Volume Profile" and 'result' not in st.session_state.results[analysis_type]:
136
- st.session_state.results[analysis_type]['result'] = calculate_volume_profile(data.copy(), n_days)
137
- elif analysis_type == "KMeans Clustering" and 'result' not in st.session_state.results[analysis_type]:
138
- st.session_state.results[analysis_type]['result'] = calculate_kmeans_clusters(data.copy(), n_days, num_clusters)
139
-
140
- # Run analysis and cache results
141
- if st.sidebar.button('Run Analysis'):
142
- if st.session_state.data is None:
143
- st.session_state.data = get_data(ticker, start_date, end_date)
144
-
145
- if not st.session_state.data.empty:
146
- cache_results_in_session(st.session_state.data, analysis_type, window_period, lookback_period, n_days, num_clusters)
147
-
148
- data = st.session_state.data
149
- result = st.session_state.results[analysis_type]['result']
150
-
151
- if analysis_type == "Pivot Points":
152
- st.write("### Pivot Points")
153
- st.markdown("""
154
- **Pivot Points** are short-term trend indicators used to determine potential support and resistance levels. The central pivot point, as well as derived support and resistance levels, are calculated using the high, low, and close prices of a previous period (usually the previous day for day trading).
155
- - **Pivot Point (P)**: The average of the high, low, and close of the previous trading period.
156
- - **First Resistance (R1)**: Calculated by doubling the pivot point and then subtracting the previous low.
157
- - **First Support (S1)**: Derived by doubling the pivot point and then subtracting the previous high.
158
- - **Second Resistance (R2)**: Obtained by adding the difference of high and low (the range) to the pivot point.
159
- - **Second Support (S2)**: Found by subtracting the range from the pivot point.
160
- """)
161
-
162
- fig1 = go.Figure()
163
- fig1.add_trace(go.Scatter(x=result.index, y=result['Close'], mode='lines', name='Close Price'))
164
- fig1.add_trace(go.Scatter(x=result.index, y=result['Pivot'], mode='lines', name='Pivot', line=dict(dash='dash', color='black')))
165
- fig1.add_trace(go.Scatter(x=result.index, y=result['R1'], mode='lines', name='Resistance 1', line=dict(dash='dash', color='red')))
166
- fig1.add_trace(go.Scatter(x=result.index, y=result['S1'], mode='lines', name='Support 1', line=dict(dash='dash', color='green')))
167
- fig1.add_trace(go.Scatter(x=result.index, y=result['R2'], mode='lines', name='Resistance 2', line=dict(dash='dash', color='orange')))
168
- fig1.add_trace(go.Scatter(x=result.index, y=result['S2'], mode='lines', name='Support 2', line=dict(dash='dash', color='blue')))
169
- fig1.update_layout(
170
- title=f'{ticker} Price with Pivot Points and Support/Resistance Levels',
171
- xaxis_title='Date',
172
- yaxis_title='Price',
173
- legend_title='Legend',
174
- width=1200,
175
- height=600
176
- )
177
- st.plotly_chart(fig1, use_container_width=True)
178
-
179
- elif analysis_type == "Support and Resistance":
180
- support, resistance, breaks_above_resistance, breaks_below_support = result
181
-
182
- st.write("### Rolling Midpoint Range")
183
- st.markdown("""
184
- **Support and Resistance Levels** This method uses a rolling window to identify these levels. This provides a dynamic approach to pinpointing key price levels.
185
- - **Support Level**: Calculated as the rolling minimum price over the specified window period. It acts as a floor where buying interest is strong enough to prevent further price declines.
186
- - **Resistance Level**: Calculated as the rolling maximum price over the specified window period. It acts as a ceiling where selling interest prevents the price from rising further.
187
- In this analysis, the support and resistance levels are determined using a rolling window approach. Significant breaks above resistance and below support are highlighted, especially when accompanied by higher-than-average trading volumes, which could indicate potential breakout or breakdown scenarios.
188
- """)
189
-
190
- fig2 = go.Figure()
191
- fig2.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
192
- fig2.add_trace(go.Scatter(x=data.index, y=support, mode='lines', name='Support', line=dict(dash='dash', color='green')))
193
- fig2.add_trace(go.Scatter(x=data.index, y=resistance, mode='lines', name='Resistance', line=dict(dash='dash', color='red')))
194
- fig2.add_trace(go.Scatter(x=data[breaks_above_resistance].index, y=data['Close'][breaks_above_resistance], mode='markers', name='Break Above Resistance', marker=dict(color='blue')))
195
- fig2.add_trace(go.Scatter(x=data[breaks_below_support].index, y=data['Close'][breaks_below_support], mode='markers', name='Break Below Support', marker=dict(color='purple')))
196
- fig2.update_layout(
197
- title=f'{ticker} Price with Support and Resistance Levels',
198
- xaxis_title='Date',
199
- yaxis_title='Price',
200
- legend_title='Legend',
201
- width=1200,
202
- height=600
203
- )
204
- st.plotly_chart(fig2, use_container_width=True)
205
-
206
- elif analysis_type == "Swing Highs and Lows":
207
- st.write("### Swing Highs and Lows")
208
- st.markdown("""
209
- **Swing Highs and Lows** are the highest and lowest points in the price action over a specified period.
210
- - **Swing High**: A peak where the price is higher than the surrounding prices.
211
- - **Swing Low**: A trough where the price is lower than the surrounding prices.
212
- """)
213
-
214
- fig3 = go.Figure()
215
- fig3.add_trace(go.Scatter(x=result.index, y=result['Close'], mode='lines', name='Close Price'))
216
- fig3.add_trace(go.Scatter(x=result.index, y=result['Swing_High'], mode='markers', name='Swing Highs', marker=dict(color='red')))
217
- fig3.add_trace(go.Scatter(x=result.index, y=result['Swing_Low'], mode='markers', name='Swing Lows', marker=dict(color='green')))
218
- fig3.update_layout(
219
- title=f'{ticker} with Swing Highs & Lows',
220
- xaxis_title='Date',
221
- yaxis_title='Price',
222
- legend_title='Legend',
223
- width=1200,
224
- height=600
225
- )
226
- st.plotly_chart(fig3, use_container_width=True)
227
-
228
- elif analysis_type == "Fibonacci Retracement Levels":
229
- fib_levels, levels = result
230
-
231
- st.write("### Fibonacci Retracement Levels")
232
- st.markdown("""
233
- **Fibonacci Retracement Levels** are horizontal lines that indicate where support and resistance are likely to occur. They are based on Fibonacci numbers and are used to predict the future movement of asset prices.
234
- - **Levels**: 23.6%, 38.2%, 50%, 61.8%, and 78.6% represent key points where the price could potentially reverse.
235
- """)
236
-
237
- fig4 = go.Figure()
238
- fig4.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
239
- color_list = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
240
- for i, (level, color) in enumerate(zip(levels, color_list)):
241
- fig4.add_trace(go.Scatter(x=data.index, y=fib_levels[:, i], mode='lines', name=f'Fib {level:.3f}', line=dict(color=color)))
242
- fig4.update_layout(
243
- title=f'{ticker} with Fibonacci Retracement Levels',
244
- xaxis_title='Date',
245
- yaxis_title='Price',
246
- legend_title='Legend',
247
- width=1200,
248
- height=600
249
- )
250
- st.plotly_chart(fig4, use_container_width=True)
251
-
252
- elif analysis_type == "Trendlines":
253
- st.write("### Trendlines with Regression Analysis")
254
- st.markdown("""
255
- **Trendlines** are straight lines drawn on a price chart to connect two or more price points. They help identify the direction of the market trend and potential areas of support and resistance. In this analysis, trendlines are determined using regression analysis to fit the lines through swing highs and lows.
256
- - **Upper Trendline**: Connects higher highs using linear regression to fit a line through these points. This line acts as a resistance level.
257
- - **Lower Trendline**: Connects lower lows using linear regression to fit a line through these points. This line acts as a support level.
258
- 1. **Swing Highs and Lows Identification**: First, local maxima (swing highs) and minima (swing lows) are identified using a specified lookback period.
259
- 2. **Linear Regression**: A linear regression is then applied to the swing highs to form the upper trendline and to the swing lows to form the lower trendline.
260
- 3. **Visualization**: The trendlines are plotted along with the stock's closing prices to represent of potential resistance and support levels.
261
- """)
262
-
263
- fig5 = go.Figure()
264
- fig5.add_trace(go.Scatter(x=result.index, y=result['Close'], mode='lines', name='Close Price'))
265
-
266
- swing_highs = result['Swing_High'].dropna()
267
- swing_lows = result['Swing_Low'].dropna()
268
-
269
- if len(swing_highs) > 1 and len(swing_lows) > 1:
270
- upper_m, upper_b = np.polyfit(swing_highs.index.map(pd.Timestamp.toordinal), swing_highs.values, 1)
271
- lower_m, lower_b = np.polyfit(swing_lows.index.map(pd.Timestamp.toordinal), swing_lows.values, 1)
272
- result['Upper_Trendline'] = upper_m * result.index.map(pd.Timestamp.toordinal) + upper_b
273
- result['Lower_Trendline'] = lower_m * result.index.map(pd.Timestamp.toordinal) + lower_b
274
- fig5.add_trace(go.Scatter(x=result.index, y=result['Upper_Trendline'], mode='lines', name='Upper Trendline', line=dict(color='orange')))
275
- fig5.add_trace(go.Scatter(x=result.index, y=result['Lower_Trendline'], mode='lines', name='Lower Trendline', line=dict(color='blue')))
276
-
277
- fig5.update_layout(
278
- title=f'{ticker} with Trendlines',
279
- xaxis_title='Date',
280
- yaxis_title='Price',
281
- legend_title='Legend',
282
- width=1200,
283
- height=600
284
- )
285
- st.plotly_chart(fig5, use_container_width=True)
286
-
287
- elif analysis_type == "Volume Profile":
288
- price_bins, volume_profile = result
289
-
290
- st.write("### Volume Profile")
291
- st.markdown("""
292
- **Volume Profile** is a charting tool that shows the amount of volume traded at different price levels over a specified period. It helps identify areas of high trading activity, which can act as support or resistance.
293
- - **High Volume Areas**: Indicate significant trading activity and can act as strong support or resistance levels.
294
- """)
295
-
296
- fig6, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(20, 5), gridspec_kw={'width_ratios': [3, 1]})
297
- ax1.plot(data['Close'], label="Close Price")
298
- current_price = data['Close'].iloc[-1]
299
- support_idx = np.argmax(volume_profile[:np.digitize(current_price, price_bins)])
300
- resistance_idx = np.argmax(volume_profile[np.digitize(current_price, price_bins):]) + np.digitize(current_price, price_bins)
301
- support_price = price_bins[support_idx]
302
- resistance_price = price_bins[resistance_idx]
303
- ax1.axhline(y=support_price, color='g', linestyle='--', label='Support')
304
- ax1.axhline(y=resistance_price, color='r', linestyle='--', label='Resistance')
305
- ax1.annotate(f'Support: {support_price:.2f}',
306
- xy=(data.index[-1], support_price),
307
- xytext=(data.index[-1], support_price - 5),
308
- arrowprops=dict(facecolor='green', arrowstyle='->'),
309
- color='green', fontsize=12)
310
- ax1.annotate(f'Resistance: {resistance_price:.2f}',
311
- xy=(data.index[-1], resistance_price),
312
- xytext=(data.index[-1], resistance_price + 5),
313
- arrowprops=dict(facecolor='red', arrowstyle='->'),
314
- color='red', fontsize=12)
315
- ax1.legend()
316
- ax1.set_title(f'{ticker} Price Data')
317
- ax2.barh(price_bins[:-1], volume_profile, height=(price_bins[1] - price_bins[0]), color='blue', edgecolor='none')
318
- ax2.set_title('Volume Profile')
319
- st.pyplot(fig6, use_container_width=True)
320
-
321
- elif analysis_type == "KMeans Clustering":
322
- cluster_centers = result
323
-
324
- st.write("### KMeans Clusters")
325
- st.markdown("""
326
- **KMeans Clustering** is a machine learning algorithm used to partition a dataset into clusters. In the context of stock prices, it helps identify patterns and group similar price movements together.
327
- - **Clusters**: Represent different regimes or phases in the stock price movements.
328
- """)
329
-
330
- fig7 = go.Figure()
331
- fig7.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price'))
332
- for center in cluster_centers:
333
- fig7.add_trace(go.Scatter(x=[data.index[-1]], y=[center], mode='markers+text', name=f'Cluster Center: {center:.2f}', text=[f'{center:.2f}'], textposition='top center'))
334
- fig7.add_shape(type="line",
335
- x0=data.index[0], x1=data.index[-1], y0=center, y1=center,
336
- line=dict(color='Red', dash="dash"))
337
- fig7.update_layout(
338
- title=f'{ticker} with KMeans Clustering (Last {n_days} Days)',
339
- xaxis_title='Date',
340
- yaxis_title='Price',
341
- legend_title='Legend',
342
- width=1200,
343
- height=600
344
- )
345
- st.plotly_chart(fig7, use_container_width=True)
346
 
347
  else:
348
  st.write("No data found for the given ticker and date range.")
349
 
350
- # Hide Streamlit style
351
  hide_streamlit_style = """
352
  <style>
353
  #MainMenu {visibility: hidden;}
354
  footer {visibility: hidden;}
355
  </style>
356
  """
357
- st.markdown(hide_streamlit_style, unsafe_allow_html=True)
 
8
  from sklearn.cluster import KMeans
9
  import matplotlib.pyplot as plt
10
 
11
+ # Streamlit app
12
+
13
  st.set_page_config(page_title="Identifying Key Support and Resistance In Price Levels", layout="wide")
14
  st.title('Key Support and Resistance In Price Levels')
15
 
 
24
  7. **KMeans Clustering**: A machine learning algorithm used to partition the dataset into clusters, identifying patterns and grouping similar price movements together to highlight significant price levels.
25
  """)
26
 
27
+ # Sidebar: How to use and Input Parameters
 
 
 
 
 
 
28
  st.sidebar.title('Input Parameters')
29
 
30
+ st.sidebar.subheader('How to use:')
31
+
32
+ st.sidebar.markdown("""
33
+ 1. **Enter Ticker**: Specify a stock ticker or crypto pair.
34
+ 2. **Set Dates**: Choose the date range for analysis.
35
+ 3. **Adjust Parameters**: Modify methodology parameters as needed.
36
+ 4. **Run Analysis**: Click 'Run' to generate results.
37
+ """)
38
+
39
+ # Expander for ticker and date settings
40
+ with st.sidebar.expander("Ticker and Date Settings", expanded=True):
41
+ st.write("Specify the ticker and date range for analysis.")
42
+ ticker = st.text_input('Stock Ticker or Crypto Pair', 'AAPL', help="Enter stock ticker (e.g., AAPL) or crypto pair (e.g., BTC-USD).")
43
+ start_date = st.date_input('Start Date', pd.to_datetime('2023-01-01'))
44
+ end_date = st.date_input('End Date', datetime.now() + timedelta(days=1))
45
+
46
+ # Expander for methodology-specific parameters
47
+ with st.sidebar.expander("Pivot Points and Levels", expanded=True):
48
+ window_period = st.slider('Window Period for Pivot Points and Levels', min_value=10, max_value=60, value=30, help="Set the window period for calculating pivot points and support/resistance levels.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
 
50
+ with st.sidebar.expander("Trendlines and Fibonacci Levels", expanded=True):
51
+ lookback_period = st.slider('Lookback Period for Trendlines and Fibonacci', min_value=10, max_value=60, value=30, help="Set the lookback period for calculating trendlines and Fibonacci retracement levels.")
52
+
53
+ with st.sidebar.expander("Volume Profile and KMeans", expanded=True):
54
+ n_days = st.slider('Lookback Period for Volume Profile and KMeans (Days)', min_value=30, max_value=365, value=60, help="Set the number of days for calculating volume profile and KMeans clustering.")
55
+ num_clusters = st.slider('Number of Clusters for KMeans', min_value=2, max_value=10, value=3, help="Set the number of clusters for KMeans analysis.")
56
+
57
+ # Define functions for different analyses
58
  def calculate_pivot_points(df, window):
59
  df['Pivot'] = df['Close'].rolling(window=window).mean()
60
  df['R1'] = 2 * df['Pivot'] - df['Low'].rolling(window=window).min()
 
102
  cluster_centers = kmeans.cluster_centers_[:, 1] * (np.max(filtered_data['Close']) - np.min(filtered_data['Close'])) + np.min(filtered_data['Close'])
103
  return cluster_centers
104
 
105
+ # Run the analysis
106
+ if st.sidebar.button('Run Analysis'):
107
+ data = yf.download(ticker, start=start_date, end=end_date)
 
108
 
109
+ if not data.empty:
110
+ # Calculate Pivot Points
111
+ df_pivot = calculate_pivot_points(data.copy(), window_period)
112
+ df_pivot = df_pivot.dropna()
113
+
114
+ # Calculate Support and Resistance Levels
115
  support, resistance = find_levels(data.copy(), window_period)
116
  breaks_above_resistance, breaks_below_support = check_significant_break(data.copy(), support, resistance)
117
+
118
+ # Calculate Swing Highs and Lows
119
+ data_with_trendlines = prepare_data_for_trendlines(data.copy(), lookback_period)
120
+
121
+ # Calculate Fibonacci Retracement Levels
122
+ fib_levels, levels = calculate_fibonacci_levels(data.copy(), lookback_period)
123
+
124
+ # Calculate Volume Profile
125
+ price_bins, volume_profile = calculate_volume_profile(data.copy(), n_days)
126
+
127
+ # Calculate KMeans Clusters
128
+ cluster_centers = calculate_kmeans_clusters(data.copy(), n_days, num_clusters)
129
+
130
+ # Plot Pivot Points
131
+ st.write("### Pivot Points")
132
+ st.markdown("""
133
+ **Pivot Points** are short-term trend indicators used to determine potential support and resistance levels. The central pivot point, as well as derived support and resistance levels, are calculated using the high, low, and close prices of a previous period (usually the previous day for day trading).
134
+ - **Pivot Point (P)**: The average of the high, low, and close of the previous trading period.
135
+ - **First Resistance (R1)**: Calculated by doubling the pivot point and then subtracting the previous low.
136
+ - **First Support (S1)**: Derived by doubling the pivot point and then subtracting the previous high.
137
+ - **Second Resistance (R2)**: Obtained by adding the difference of high and low (the range) to the pivot point.
138
+ - **Second Support (S2)**: Found by subtracting the range from the pivot point.
139
+ """)
140
+
141
+ fig1 = go.Figure()
142
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['Close'], mode='lines', name='Close Price'))
143
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['Pivot'], mode='lines', name='Pivot', line=dict(dash='dash', color='black')))
144
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['R1'], mode='lines', name='Resistance 1', line=dict(dash='dash', color='red')))
145
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['S1'], mode='lines', name='Support 1', line=dict(dash='dash', color='green')))
146
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['R2'], mode='lines', name='Resistance 2', line=dict(dash='dash', color='orange')))
147
+ fig1.add_trace(go.Scatter(x=df_pivot.index, y=df_pivot['S2'], mode='lines', name='Support 2', line=dict(dash='dash', color='blue')))
148
+ fig1.update_layout(
149
+ title=f'{ticker} Price with Pivot Points and Support/Resistance Levels',
150
+ xaxis_title='Date',
151
+ yaxis_title='Price',
152
+ legend_title='Legend',
153
+ width=1200, # Set desired width
154
+ height=600 # Set desired height
155
+ )
156
+ st.plotly_chart(fig1, use_container_width=True)
157
+
158
+ # Plot Support and Resistance Levels using Rolling Midpoint Range
159
+ st.write("### Rolling Midpoint Range")
160
+ st.markdown("""
161
+ **Support and Resistance Levels** This method uses a rolling window to identify these levels. This provides a dynamic approach to pinpointing key price levels.
162
+ - **Support Level**: Calculated as the rolling minimum price over the specified window period. It acts as a floor where buying interest is strong enough to prevent further price declines.
163
+ - **Resistance Level**: Calculated as the rolling maximum price over the specified window period. It acts as a ceiling where selling interest prevents the price from rising further.
164
+ In this analysis, the support and resistance levels are determined using a rolling window approach. Significant breaks above resistance and below support are highlighted, especially when accompanied by higher-than-average trading volumes, which could indicate potential breakout or breakdown scenarios.
165
+ """)
166
+
167
+ fig2 = go.Figure()
168
+ fig2.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
169
+ fig2.add_trace(go.Scatter(x=data.index, y=support, mode='lines', name='Support', line=dict(dash='dash', color='green')))
170
+ fig2.add_trace(go.Scatter(x=data.index, y=resistance, mode='lines', name='Resistance', line=dict(dash='dash', color='red')))
171
+ fig2.add_trace(go.Scatter(x=data[breaks_above_resistance].index, y=data['Close'][breaks_above_resistance], mode='markers', name='Break Above Resistance', marker=dict(color='blue')))
172
+ fig2.add_trace(go.Scatter(x=data[breaks_below_support].index, y=data['Close'][breaks_below_support], mode='markers', name='Break Below Support', marker=dict(color='purple')))
173
+ fig2.update_layout(
174
+ title=f'{ticker} Price with Support and Resistance Levels',
175
+ xaxis_title='Date',
176
+ yaxis_title='Price',
177
+ legend_title='Legend',
178
+ width=1200, # Set desired width
179
+ height=600 # Set desired height
180
+ )
181
+ st.plotly_chart(fig2, use_container_width=True)
182
+
183
+ # Plot Swing Highs and Lows
184
+ st.write("### Swing Highs and Lows")
185
+ st.markdown("""
186
+ **Swing Highs and Lows** are the highest and lowest points in the price action over a specified period.
187
+ - **Swing High**: A peak where the price is higher than the surrounding prices.
188
+ - **Swing Low**: A trough where the price is lower than the surrounding prices.
189
+ """)
190
+
191
+ fig3 = go.Figure()
192
+ fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Close'], mode='lines', name='Close Price'))
193
+ fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Swing_High'], mode='markers', name='Swing Highs', marker=dict(color='red')))
194
+ fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Swing_Low'], mode='markers', name='Swing Lows', marker=dict(color='green')))
195
+ fig3.update_layout(
196
+ title=f'{ticker} with Swing Highs & Lows',
197
+ xaxis_title='Date',
198
+ yaxis_title='Price',
199
+ legend_title='Legend',
200
+ width=1200, # Set desired width
201
+ height=600 # Set desired height
202
+ )
203
+ st.plotly_chart(fig3, use_container_width=True)
204
+
205
+ # Plot Fibonacci Retracement Levels
206
+ st.write("### Fibonacci Retracement Levels")
207
+ st.markdown("""
208
+ **Fibonacci Retracement Levels** are horizontal lines that indicate where support and resistance are likely to occur. They are based on Fibonacci numbers and are used to predict the future movement of asset prices.
209
+ - **Levels**: 23.6%, 38.2%, 50%, 61.8%, and 78.6% represent key points where the price could potentially reverse.
210
+ """)
211
+
212
+ fig4 = go.Figure()
213
+ fig4.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
214
+ color_list = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
215
+ for i, (level, color) in enumerate(zip(levels, color_list)):
216
+ fig4.add_trace(go.Scatter(x=data.index, y=fib_levels[:, i], mode='lines', name=f'Fib {level:.3f}', line=dict(color=color)))
217
+ fig4.update_layout(
218
+ title=f'{ticker} with Fibonacci Retracement Levels',
219
+ xaxis_title='Date',
220
+ yaxis_title='Price',
221
+ legend_title='Legend',
222
+ width=1200, # Set desired width
223
+ height=600 # Set desired height
224
+ )
225
+ st.plotly_chart(fig4, use_container_width=True)
226
+
227
+ # Plot Trendlines
228
+ st.write("### Trendlines with Regression Analysis")
229
+ st.markdown("""
230
+ **Trendlines** are straight lines drawn on a price chart to connect two or more price points. They help identify the direction of the market trend and potential areas of support and resistance. In this analysis, trendlines are determined using regression analysis to fit the lines through swing highs and lows.
231
+ - **Upper Trendline**: Connects higher highs using linear regression to fit a line through these points. This line acts as a resistance level.
232
+ - **Lower Trendline**: Connects lower lows using linear regression to fit a line through these points. This line acts as a support level.
233
+ 1. **Swing Highs and Lows Identification**: First, local maxima (swing highs) and minima (swing lows) are identified using a specified lookback period.
234
+ 2. **Linear Regression**: A linear regression is then applied to the swing highs to form the upper trendline and to the swing lows to form the lower trendline.
235
+ 3. **Visualization**: The trendlines are plotted along with the stock's closing prices to represent of potential resistance and support levels.
236
+ """)
237
+
238
+ fig5 = go.Figure()
239
+ fig5.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Close'], mode='lines', name='Close Price'))
240
+
241
+ swing_highs = data_with_trendlines['Swing_High'].dropna()
242
+ swing_lows = data_with_trendlines['Swing_Low'].dropna()
243
+
244
+ if len(swing_highs) > 1 and len(swing_lows) > 1:
245
+ upper_m, upper_b = np.polyfit(swing_highs.index.map(pd.Timestamp.toordinal), swing_highs.values, 1)
246
+ lower_m, lower_b = np.polyfit(swing_lows.index.map(pd.Timestamp.toordinal), swing_lows.values, 1)
247
+ data_with_trendlines['Upper_Trendline'] = upper_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + upper_b
248
+ data_with_trendlines['Lower_Trendline'] = lower_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + lower_b
249
+ fig5.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Upper_Trendline'], mode='lines', name='Upper Trendline', line=dict(color='orange')))
250
+ fig5.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Lower_Trendline'], mode='lines', name='Lower Trendline', line=dict(color='blue')))
251
+
252
+ fig5.update_layout(
253
+ title=f'{ticker} with Trendlines',
254
+ xaxis_title='Date',
255
+ yaxis_title='Price',
256
+ legend_title='Legend',
257
+ width=1200, # Set desired width
258
+ height=600 # Set desired height
259
+ )
260
+ st.plotly_chart(fig5, use_container_width=True)
261
+
262
+ # Plot Volume Profile
263
+ st.write("### Volume Profile")
264
+ st.markdown("""
265
+ **Volume Profile** is a charting tool that shows the amount of volume traded at different price levels over a specified period. It helps identify areas of high trading activity, which can act as support or resistance.
266
+ - **High Volume Areas**: Indicate significant trading activity and can act as strong support or resistance levels.
267
+ """)
268
+
269
+ fig6, (ax1, ax2) = plt.subplots(nrows=1, ncols=2, figsize=(20, 5), gridspec_kw={'width_ratios': [3, 1]})
270
+ ax1.plot(data['Close'], label="Close Price")
271
+ current_price = data['Close'].iloc[-1]
272
+ support_idx = np.argmax(volume_profile[:np.digitize(current_price, price_bins)])
273
+ resistance_idx = np.argmax(volume_profile[np.digitize(current_price, price_bins):]) + np.digitize(current_price, price_bins)
274
+ support_price = price_bins[support_idx]
275
+ resistance_price = price_bins[resistance_idx]
276
+ ax1.axhline(y=support_price, color='g', linestyle='--', label='Support')
277
+ ax1.axhline(y=resistance_price, color='r', linestyle='--', label='Resistance')
278
+ ax1.annotate(f'Support: {support_price:.2f}',
279
+ xy=(data.index[-1], support_price),
280
+ xytext=(data.index[-1], support_price - 5),
281
+ arrowprops=dict(facecolor='green', arrowstyle='->'),
282
+ color='green', fontsize=12)
283
+ ax1.annotate(f'Resistance: {resistance_price:.2f}',
284
+ xy=(data.index[-1], resistance_price),
285
+ xytext=(data.index[-1], resistance_price + 5),
286
+ arrowprops=dict(facecolor='red', arrowstyle='->'),
287
+ color='red', fontsize=12)
288
+ ax1.legend()
289
+ ax1.set_title(f'{ticker} Price Data')
290
+ ax2.barh(price_bins[:-1], volume_profile, height=(price_bins[1] - price_bins[0]), color='blue', edgecolor='none')
291
+ ax2.set_title('Volume Profile')
292
+ st.pyplot(fig6, use_container_width=True)
293
+
294
+ # Plot KMeans Clusters
295
+ st.write("### KMeans Clusters")
296
+ st.markdown("""
297
+ **KMeans Clustering** is a machine learning algorithm used to partition a dataset into clusters. In the context of stock prices, it helps identify patterns and group similar price movements together.
298
+ - **Clusters**: Represent different regimes or phases in the stock price movements.
299
+ """)
300
+
301
+ fig7 = go.Figure()
302
+ fig7.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Close Price'))
303
+ for center in cluster_centers:
304
+ fig7.add_trace(go.Scatter(x=[data.index[-1]], y=[center], mode='markers+text', name=f'Cluster Center: {center:.2f}', text=[f'{center:.2f}'], textposition='top center'))
305
+ fig7.add_shape(type="line",
306
+ x0=data.index[0], x1=data.index[-1], y0=center, y1=center,
307
+ line=dict(color='Red', dash="dash"))
308
+ fig7.update_layout(
309
+ title=f'{ticker} with KMeans Clustering (Last {n_days} Days)',
310
+ xaxis_title='Date',
311
+ yaxis_title='Price',
312
+ legend_title='Legend',
313
+ width=1200, # Set desired width
314
+ height=600 # Set desired height
315
+ )
316
+ st.plotly_chart(fig7, use_container_width=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
 
318
  else:
319
  st.write("No data found for the given ticker and date range.")
320
 
 
321
  hide_streamlit_style = """
322
  <style>
323
  #MainMenu {visibility: hidden;}
324
  footer {visibility: hidden;}
325
  </style>
326
  """
327
+ st.markdown(hide_streamlit_style, unsafe_allow_html=True)