How to Calculate Support and Resistance Levels Using Python: A Step-by-Step Guide

ยท

Support and resistance levels are foundational tools in technical analysis, helping traders identify potential reversal points in price trends. These levels are derived from historical price data and can significantly enhance trading strategies by pinpointing optimal entry and exit points.


Key Concepts: Support and Resistance


Implementation in Python

1. Install Required Packages

pip install yahooquery pandas scipy mplfinance

2. Import Libraries

import yahooquery as yq
import pandas as pd
import scipy as sp
import mplfinance as mpf

3. Load Historical Data

bars = yq.Ticker('AAPL').history(start='2022-01-01', interval='1d').reset_index(level=0, drop=True)

4. Visualize Price Data

Plot candlestick charts to contextualize price movements:

bars.index = pd.to_datetime(bars.index)
mpf.plot(bars, type='candle', style='charles', title='AAPL Candlestick Chart', volume=True)

Identifying Resistance Levels

Strong Peaks

Resistance levels with high prominence and separation:

strong_peaks_distance = 60  # Minimum days between peaks
strong_peaks_prominence = 20  # Peak significance threshold

strong_peaks, _ = sp.signal.find_peaks(
    bars['high'],
    distance=strong_peaks_distance,
    prominence=strong_peaks_prominence
)
strong_peaks_values = bars.iloc[strong_peaks]["high"].values.tolist()
yearly_high = bars["high"].iloc[-252:].max()
strong_peaks_values.append(yearly_high)

General Peaks

Shorter-term resistance levels with weaker prominence:

peak_distance = 5  # Days between peaks
peak_rank_width = 2  # Price range for merging peaks
resistance_min_pivot_rank = 3  # Minimum rejections to qualify as resistance

peaks, _ = sp.signal.find_peaks(bars['high'], distance=peak_distance)
peak_to_rank = {peak: 0 for peak in peaks}

for i, current_peak in enumerate(peaks):
    current_high = bars.iloc[current_peak]["high"]
    for previous_peak in peaks[:i]:
        if abs(current_high - bars.iloc[previous_peak]["high"]) <= peak_rank_width:
            peak_to_rank[current_peak] += 1

resistances = strong_peaks_values
for peak, rank in peak_to_rank.items():
    if rank >= resistance_min_pivot_rank:
        resistances.append(bars.iloc[peak]["high"] + 1e-3)
resistances.sort()

Merge Nearby Peaks

resistance_bins = []
current_bin = [resistances[0]]
for r in resistances:
    if r - current_bin[-1] < peak_rank_width:
        current_bin.append(r)
    else:
        resistance_bins.append(current_bin)
        current_bin = [r]
resistance_bins.append(current_bin)
resistances = [np.mean(bin) for bin in resistance_bins]

Identifying Support Levels

Apply the same methodology to troughs (price lows):

troughs, _ = sp.signal.find_peaks(-bars['low'], distance=peak_distance)

Conclusion

This guide demonstrates how to programmatically identify support and resistance levels using Python. By combining strong peaks (long-term resistances) and general peaks (short-term rejections), traders gain a comprehensive view of key price levels.

๐Ÿ‘‰ Explore advanced trading strategies


FAQs

Q1: Can this method be applied to intraday trading?
A: Yes! Adjust the interval parameter in yq.Ticker() to shorter time frames (e.g., 5m for 5-minute bars).

Q2: How do I avoid overfitting resistance levels?
A: Tweak peak_distance and prominence to filter out insignificant peaks.

Q3: What other indicators complement support/resistance analysis?
A: Volume analysis and moving averages enhance the reliability of these levels.

Q4: Why merge nearby peaks?
A: Merging reduces noise, creating cleaner, more actionable resistance levels.

Q5: How often should I recalculate these levels?
A: Update them periodically (e.g., weekly) to reflect recent price action.

Q6: Can this be automated for multiple stocks?
A: Absolutely. Wrap the code in a loop to process multiple tickers.


๐Ÿ‘‰ Master Python for trading with real-world examples. Happy coding!