Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -13,7 +13,14 @@ st.set_page_config(page_title="Identifying Key Support and Resistance In Price L
|
|
| 13 |
st.title('Key Support and Resistance In Price Levels')
|
| 14 |
|
| 15 |
st.markdown("""
|
| 16 |
-
This tool aims to identify key support and resistance price levels in stocks using various algorithmic methods.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
""")
|
| 18 |
|
| 19 |
# Sidebar for input parameters
|
|
@@ -45,8 +52,8 @@ with st.sidebar:
|
|
| 45 |
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.")
|
| 46 |
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.")
|
| 47 |
|
| 48 |
-
# Select analysis type
|
| 49 |
-
analysis_type = st.
|
| 50 |
|
| 51 |
# Function to fetch and cache data
|
| 52 |
@st.cache_data
|
|
@@ -56,6 +63,54 @@ def get_data(ticker, start_date, end_date):
|
|
| 56 |
st.error("No data found for the given ticker and date range.")
|
| 57 |
return data
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
# Run analysis only if the user clicks the "Run Analysis" button
|
| 60 |
if st.sidebar.button('Run Analysis'):
|
| 61 |
data = get_data(ticker, start_date, end_date)
|
|
@@ -133,7 +188,7 @@ if st.sidebar.button('Run Analysis'):
|
|
| 133 |
fig3 = go.Figure()
|
| 134 |
fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Close'], mode='lines', name='Close Price'))
|
| 135 |
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')))
|
| 136 |
-
fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Swing_Low'], mode='markers', name='Swing Lows', marker
|
| 137 |
fig3.update_layout(
|
| 138 |
title=f'{ticker} with Swing Highs & Lows',
|
| 139 |
xaxis_title='Date',
|
|
@@ -157,7 +212,7 @@ if st.sidebar.button('Run Analysis'):
|
|
| 157 |
fig4.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
|
| 158 |
color_list = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
|
| 159 |
for i, (level, color) in enumerate(zip(levels, color_list)):
|
| 160 |
-
fig4.add_trace(go.Scatter(x=data.index, y=fib_levels[:, i], mode='lines', name=f'Fib {level:.3f}', line
|
| 161 |
fig4.update_layout(
|
| 162 |
title=f'{ticker} with Fibonacci Retracement Levels',
|
| 163 |
xaxis_title='Date',
|
|
@@ -192,8 +247,8 @@ if st.sidebar.button('Run Analysis'):
|
|
| 192 |
lower_m, lower_b = np.polyfit(swing_lows.index.map(pd.Timestamp.toordinal), swing_lows.values, 1)
|
| 193 |
data_with_trendlines['Upper_Trendline'] = upper_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + upper_b
|
| 194 |
data_with_trendlines['Lower_Trendline'] = lower_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + lower_b
|
| 195 |
-
fig5.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Upper_Trendline'], mode='lines', name='Upper Trendline', line
|
| 196 |
-
fig5.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Lower_Trendline'], mode='lines', name='Lower Trendline', line
|
| 197 |
|
| 198 |
fig5.update_layout(
|
| 199 |
title=f'{ticker} with Trendlines',
|
|
@@ -254,7 +309,7 @@ if st.sidebar.button('Run Analysis'):
|
|
| 254 |
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'))
|
| 255 |
fig7.add_shape(type="line",
|
| 256 |
x0=data.index[0], x1=data.index[-1], y0=center, y1=center,
|
| 257 |
-
line
|
| 258 |
fig7.update_layout(
|
| 259 |
title=f'{ticker} with KMeans Clustering (Last {n_days} Days)',
|
| 260 |
xaxis_title='Date',
|
|
@@ -264,6 +319,7 @@ if st.sidebar.button('Run Analysis'):
|
|
| 264 |
height=600
|
| 265 |
)
|
| 266 |
st.plotly_chart(fig7, use_container_width=True)
|
|
|
|
| 267 |
else:
|
| 268 |
st.write("No data found for the given ticker and date range.")
|
| 269 |
|
|
|
|
| 13 |
st.title('Key Support and Resistance In Price Levels')
|
| 14 |
|
| 15 |
st.markdown("""
|
| 16 |
+
This tool aims to identify key support and resistance price levels in stocks using various algorithmic methods. Each method is detailed below:
|
| 17 |
+
1. **Pivot Points**: Short-term trend indicators used to determine potential support and resistance levels based on the high, low, and close prices of previous trading sessions.
|
| 18 |
+
2. **Support and Resistance Levels using Rolling Midpoint Range**: Key price points where the stock's price tends to halt its upward or downward trajectory, identified using a rolling window to calculate dynamic support and resistance levels.
|
| 19 |
+
3. **Swing Highs and Lows**: Local maxima and minima used to identify trends and potential reversal points by pinpointing key inflection points on a stock's chart.
|
| 20 |
+
4. **Fibonacci Retracement Levels**: Horizontal lines indicating potential support and resistance levels based on Fibonacci numbers, helping to identify prospective market reversal points.
|
| 21 |
+
5. **Trendlines**: Straight lines drawn to connect two or more price points, helping identify the market trend direction and potential areas of support and resistance.
|
| 22 |
+
6. **Volume Profile**: A charting tool that shows the amount of volume traded at different price levels over a specified period, helping identify areas of high trading activity which can act as support or resistance.
|
| 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 |
# Sidebar for input parameters
|
|
|
|
| 52 |
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.")
|
| 53 |
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.")
|
| 54 |
|
| 55 |
+
# Select the page (analysis type)
|
| 56 |
+
analysis_type = st.radio("Select Analysis", ["Pivot Points", "Support and Resistance", "Swing Highs and Lows", "Fibonacci Retracement Levels", "Trendlines", "Volume Profile", "KMeans Clustering"])
|
| 57 |
|
| 58 |
# Function to fetch and cache data
|
| 59 |
@st.cache_data
|
|
|
|
| 63 |
st.error("No data found for the given ticker and date range.")
|
| 64 |
return data
|
| 65 |
|
| 66 |
+
# Functions for different analyses
|
| 67 |
+
def calculate_pivot_points(df, window):
|
| 68 |
+
df['Pivot'] = df['Close'].rolling(window=window).mean()
|
| 69 |
+
df['R1'] = 2 * df['Pivot'] - df['Low'].rolling(window=window).min()
|
| 70 |
+
df['S1'] = 2 * df['Pivot'] - df['High'].rolling(window=window).max()
|
| 71 |
+
df['R2'] = df['Pivot'] + (df['High'].rolling(window=window).max() - df['Low'].rolling(window=window).min())
|
| 72 |
+
df['S2'] = df['Pivot'] - (df['High'].rolling(window=window).max() - df['Low'].rolling(window=window).min())
|
| 73 |
+
return df
|
| 74 |
+
|
| 75 |
+
def find_levels(data, window):
|
| 76 |
+
resistance = data['High'].rolling(window=window).max()
|
| 77 |
+
support = data['Low'].rolling(window=window).min()
|
| 78 |
+
return support, resistance
|
| 79 |
+
|
| 80 |
+
def check_significant_break(data, support, resistance):
|
| 81 |
+
breaks_above_resistance = (data['Close'] > resistance.shift(1)) & (data['Volume'] > data['Volume'].rolling(window=30).mean())
|
| 82 |
+
breaks_below_support = (data['Close'] < support.shift(1)) & (data['Volume'] > data['Volume'].rolling(window=30).mean())
|
| 83 |
+
return breaks_above_resistance, breaks_below_support
|
| 84 |
+
|
| 85 |
+
def prepare_data_for_trendlines(data, lookback_period):
|
| 86 |
+
data['Swing_High'] = data['High'][argrelextrema(data['High'].values, np.greater_equal, order=lookback_period)[0]]
|
| 87 |
+
data['Swing_Low'] = data['Low'][argrelextrema(data['Low'].values, np.less_equal, order=lookback_period)[0]]
|
| 88 |
+
return data
|
| 89 |
+
|
| 90 |
+
def calculate_fibonacci_levels(data, lookback_period):
|
| 91 |
+
high_prices = data["High"].rolling(window=lookback_period).max()
|
| 92 |
+
low_prices = data["Low"].rolling(window=lookback_period).min()
|
| 93 |
+
price_diff = high_prices - low_prices
|
| 94 |
+
levels = np.array([0, 0.236, 0.382, 0.5, 0.618, 0.786, 1])
|
| 95 |
+
fib_levels = low_prices.values.reshape(-1, 1) + price_diff.values.reshape(-1, 1) * levels
|
| 96 |
+
return fib_levels, levels
|
| 97 |
+
|
| 98 |
+
def calculate_volume_profile(data, n_days):
|
| 99 |
+
filtered_data = data[-n_days:]
|
| 100 |
+
price_bins = np.linspace(filtered_data['Low'].min(), filtered_data['High'].max(), 100)
|
| 101 |
+
volume_profile = [filtered_data['Volume'][(filtered_data['Close'] > price_bins[i]) & (filtered_data['Close'] <= price_bins[i+1])].sum() for i in range(len(price_bins)-1)]
|
| 102 |
+
return price_bins, volume_profile
|
| 103 |
+
|
| 104 |
+
def calculate_kmeans_clusters(data, n_days, num_clusters):
|
| 105 |
+
filtered_data = data[-n_days:]
|
| 106 |
+
X_time = np.linspace(0, 1, len(filtered_data)).reshape(-1, 1)
|
| 107 |
+
X_price = (filtered_data['Close'].values - np.min(filtered_data['Close'])) / (np.max(filtered_data['Close']) - np.min(filtered_data['Close']))
|
| 108 |
+
X_cluster = np.column_stack((X_time, X_price))
|
| 109 |
+
kmeans = KMeans(n_clusters=num_clusters)
|
| 110 |
+
kmeans.fit(X_cluster)
|
| 111 |
+
cluster_centers = kmeans.cluster_centers_[:, 1] * (np.max(filtered_data['Close']) - np.min(filtered_data['Close'])) + np.min(filtered_data['Close'])
|
| 112 |
+
return cluster_centers
|
| 113 |
+
|
| 114 |
# Run analysis only if the user clicks the "Run Analysis" button
|
| 115 |
if st.sidebar.button('Run Analysis'):
|
| 116 |
data = get_data(ticker, start_date, end_date)
|
|
|
|
| 188 |
fig3 = go.Figure()
|
| 189 |
fig3.add_trace(go.Scatter(x=data_with_trendlines.index, y=data_with_trendlines['Close'], mode='lines', name='Close Price'))
|
| 190 |
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')))
|
| 191 |
+
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')))
|
| 192 |
fig3.update_layout(
|
| 193 |
title=f'{ticker} with Swing Highs & Lows',
|
| 194 |
xaxis_title='Date',
|
|
|
|
| 212 |
fig4.add_trace(go.Scatter(x=data.index, y=data['Close'], mode='lines', name='Stock Price'))
|
| 213 |
color_list = ['red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet']
|
| 214 |
for i, (level, color) in enumerate(zip(levels, color_list)):
|
| 215 |
+
fig4.add_trace(go.Scatter(x=data.index, y=fib_levels[:, i], mode='lines', name=f'Fib {level:.3f}', line.dict(color=color)))
|
| 216 |
fig4.update_layout(
|
| 217 |
title=f'{ticker} with Fibonacci Retracement Levels',
|
| 218 |
xaxis_title='Date',
|
|
|
|
| 247 |
lower_m, lower_b = np.polyfit(swing_lows.index.map(pd.Timestamp.toordinal), swing_lows.values, 1)
|
| 248 |
data_with_trendlines['Upper_Trendline'] = upper_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + upper_b
|
| 249 |
data_with_trendlines['Lower_Trendline'] = lower_m * data_with_trendlines.index.map(pd.Timestamp.toordinal) + lower_b
|
| 250 |
+
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')))
|
| 251 |
+
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')))
|
| 252 |
|
| 253 |
fig5.update_layout(
|
| 254 |
title=f'{ticker} with Trendlines',
|
|
|
|
| 309 |
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'))
|
| 310 |
fig7.add_shape(type="line",
|
| 311 |
x0=data.index[0], x1=data.index[-1], y0=center, y1=center,
|
| 312 |
+
line.dict(color='Red', dash="dash"))
|
| 313 |
fig7.update_layout(
|
| 314 |
title=f'{ticker} with KMeans Clustering (Last {n_days} Days)',
|
| 315 |
xaxis_title='Date',
|
|
|
|
| 319 |
height=600
|
| 320 |
)
|
| 321 |
st.plotly_chart(fig7, use_container_width=True)
|
| 322 |
+
|
| 323 |
else:
|
| 324 |
st.write("No data found for the given ticker and date range.")
|
| 325 |
|