SuperTrend

Haiyue
13min

SuperTrend

Indicator Overview
  • Category: Trend — Overlay Indicator
  • Default Parameters: period=10, multiplier=3
  • Output: A single trend line (above or below price)
  • Applicable Markets: Stocks, Futures, Forex, Cryptocurrencies

I. What is SuperTrend

SuperTrend is a trend-following indicator based on ATR (Average True Range). It draws a single line on the price chart: when the market is in an uptrend, the line appears below the price (typically green); when the market is in a downtrend, it appears above the price (typically red).

SuperTrend draws design inspiration from the combination of Parabolic SAR and ATR channels. Unlike SAR, SuperTrend uses ATR to adapt to market volatility, avoiding the issue of SAR clinging too tightly to price near the end of a trend due to an excessively large acceleration factor. Its core concept is:

  1. Use the price midpoint as the baseline
  2. Offset by multiplier×ATRmultiplier \times ATR in both directions to form upper and lower bands
  3. Dynamically switch trend direction based on the price’s relationship with the bands

With minimal parameters, clear logic, and unambiguous signals, SuperTrend is extremely popular in quantitative and intraday trading, especially among the Indian stock market’s intraday trading community.

Relationship to Classic Indicators

SuperTrend is essentially a smart-switching version of ATR channels. A standard ATR channel (like Keltner Channel) displays both upper and lower bands simultaneously, while SuperTrend shows only one based on the trend direction, making the signal more intuitive.

II. Mathematical Principles and Calculation

Prerequisite: ATR

First, calculate ATR (Average True Range). True Range (TR) is defined as:

TRt=max(HightLowt, HightCloset1, LowtCloset1)TR_t = \max(High_t - Low_t, \ |High_t - Close_{t-1}|, \ |Low_t - Close_{t-1}|)

ATRt=1ni=tn+1tTRi(simple average)ATR_t = \frac{1}{n}\sum_{i=t-n+1}^{t} TR_i \quad \text{(simple average)}

Or using RMA/Wilder smoothing:

ATRt=(n1)×ATRt1+TRtnATR_t = \frac{(n-1) \times ATR_{t-1} + TR_t}{n}

Basic Upper and Lower Bands

BasicUpperBandt=Hight+Lowt2+multiplier×ATRtBasicUpperBand_t = \frac{High_t + Low_t}{2} + multiplier \times ATR_t

BasicLowerBandt=Hight+Lowt2multiplier×ATRtBasicLowerBand_t = \frac{High_t + Low_t}{2} - multiplier \times ATR_t

Final Bands (Anti-Rollback)

The core rule for the final upper band is: it can only decrease, never increase (tightening the stop in a downtrend).

FinalUpperBandt={BasicUpperBandtif BasicUpperBandt<FinalUpperBandt1or Closet1>FinalUpperBandt1FinalUpperBandt1otherwiseFinalUpperBand_t = \begin{cases} BasicUpperBand_t & \text{if } BasicUpperBand_t < FinalUpperBand_{t-1} \\ & \text{or } Close_{t-1} > FinalUpperBand_{t-1} \\ FinalUpperBand_{t-1} & \text{otherwise} \end{cases}

The rule for the final lower band is the opposite: it can only increase, never decrease (raising the stop in an uptrend).

FinalLowerBandt={BasicLowerBandtif BasicLowerBandt>FinalLowerBandt1or Closet1<FinalLowerBandt1FinalLowerBandt1otherwiseFinalLowerBand_t = \begin{cases} BasicLowerBand_t & \text{if } BasicLowerBand_t > FinalLowerBand_{t-1} \\ & \text{or } Close_{t-1} < FinalLowerBand_{t-1} \\ FinalLowerBand_{t-1} & \text{otherwise} \end{cases}

SuperTrend Value

SuperTrendt={FinalUpperBandtif trend is bearishFinalLowerBandtif trend is bullishSuperTrend_t = \begin{cases} FinalUpperBand_t & \text{if trend is bearish} \\ FinalLowerBand_t & \text{if trend is bullish} \end{cases}

Trend Determination Rules

  • If Closet>FinalUpperBandtClose_t > FinalUpperBand_t —> Switch to uptrend (bullish)
  • If Closet<FinalLowerBandtClose_t < FinalLowerBand_t —> Switch to downtrend (bearish)
  • Otherwise —> Maintain the previous trend direction

Calculation Steps

  1. Calculate True Range and ATR(period) for each bar
  2. Compute basic upper and lower bands using (High+Low)/2±multiplier×ATR(High + Low)/2 \pm multiplier \times ATR
  3. Apply the anti-rollback rules to obtain the final bands
  4. Compare the closing price with the final bands to determine trend direction
  5. Select the upper or lower band as the SuperTrend value based on trend direction

III. Python Implementation

import numpy as np
import pandas as pd

def supertrend(df: pd.DataFrame,
               period: int = 10,
               multiplier: float = 3.0) -> pd.DataFrame:
    """
    Calculate the SuperTrend indicator.

    Parameters
    ----------
    df : DataFrame, must contain 'high', 'low', 'close' columns
    period : ATR period, default 10
    multiplier : ATR multiplier, default 3.0

    Returns
    ----------
    DataFrame with 'supertrend', 'trend', 'upper_band', 'lower_band' columns
    trend: 1 indicates uptrend (bullish), -1 indicates downtrend (bearish)
    """
    high = df['high'].values
    low = df['low'].values
    close = df['close'].values
    n = len(df)

    # ---------- Calculate ATR ----------
    tr = np.zeros(n)
    tr[0] = high[0] - low[0]
    for i in range(1, n):
        tr[i] = max(high[i] - low[i],
                     abs(high[i] - close[i - 1]),
                     abs(low[i] - close[i - 1]))

    # Use RMA (Wilder smoothing) for ATR
    atr = np.zeros(n)
    atr[:period] = np.nan
    atr[period - 1] = np.mean(tr[:period])
    for i in range(period, n):
        atr[i] = (atr[i - 1] * (period - 1) + tr[i]) / period

    # ---------- Basic upper and lower bands ----------
    hl2 = (high + low) / 2
    basic_upper = hl2 + multiplier * atr
    basic_lower = hl2 - multiplier * atr

    # ---------- Final upper and lower bands ----------
    final_upper = np.full(n, np.nan)
    final_lower = np.full(n, np.nan)
    supertrend_val = np.full(n, np.nan)
    trend = np.zeros(n, dtype=int)

    # Initialization
    final_upper[period - 1] = basic_upper[period - 1]
    final_lower[period - 1] = basic_lower[period - 1]
    trend[period - 1] = 1  # Assume initial uptrend

    for i in range(period, n):
        # Final upper band: only allowed to decrease or reset on breakout
        if basic_upper[i] < final_upper[i - 1] or close[i - 1] > final_upper[i - 1]:
            final_upper[i] = basic_upper[i]
        else:
            final_upper[i] = final_upper[i - 1]

        # Final lower band: only allowed to increase or reset on breakdown
        if basic_lower[i] > final_lower[i - 1] or close[i - 1] < final_lower[i - 1]:
            final_lower[i] = basic_lower[i]
        else:
            final_lower[i] = final_lower[i - 1]

        # Determine trend direction
        if trend[i - 1] == 1:
            # Previous period was uptrend
            if close[i] < final_lower[i]:
                trend[i] = -1   # Switch to downtrend
            else:
                trend[i] = 1    # Maintain uptrend
        else:
            # Previous period was downtrend
            if close[i] > final_upper[i]:
                trend[i] = 1    # Switch to uptrend
            else:
                trend[i] = -1   # Maintain downtrend

        # SuperTrend value
        if trend[i] == 1:
            supertrend_val[i] = final_lower[i]
        else:
            supertrend_val[i] = final_upper[i]

    result = pd.DataFrame({
        'supertrend': supertrend_val,
        'trend': trend,
        'upper_band': final_upper,
        'lower_band': final_lower,
        'atr': atr
    }, index=df.index)

    return result


# ========== Usage Example ==========
if __name__ == "__main__":
    np.random.seed(42)
    n = 120
    dates = pd.date_range('2024-01-01', periods=n, freq='B')

    # Simulate OHLCV data (with trend)
    trend_component = np.linspace(0, 15, n) + 5 * np.sin(np.linspace(0, 4 * np.pi, n))
    noise = np.cumsum(np.random.randn(n) * 0.4)
    price = 100 + trend_component + noise

    df = pd.DataFrame({
        'open':  price + np.random.uniform(-0.5, 0.5, n),
        'high':  price + np.abs(np.random.randn(n)) * 1.5,
        'low':   price - np.abs(np.random.randn(n)) * 1.5,
        'close': price + np.random.uniform(-0.3, 0.3, n),
        'volume': np.random.randint(1000, 5000, n)
    }, index=dates)

    st = supertrend(df, period=10, multiplier=3.0)
    merged = df.join(st)

    print("SuperTrend data for the last 15 periods:")
    print(merged[['close', 'supertrend', 'trend', 'atr']].tail(15).to_string())

    # Count buy/sell signals
    signals = merged['trend'].diff()
    buy_signals = (signals == 2).sum()    # -1 -> 1
    sell_signals = (signals == -2).sum()  # 1 -> -1
    print(f"\nNumber of buy signals: {buy_signals}")
    print(f"Number of sell signals: {sell_signals}")
Parameter Tuning Advice
  • A larger multiplier places the SuperTrend line further from price, yielding fewer but more reliable signals
  • A smaller multiplier generates more frequent signals but also more false ones
  • Common parameter combinations: (10, 3), (10, 2), (7, 3), (14, 2)
  • Optimize through backtesting based on the asset’s volatility characteristics

IV. Problems the Indicator Solves

1. Trend Direction Identification

SuperTrend provides a binary trend state:

  • Green line below price —> Uptrend, consider holding long or staying out
  • Red line above price —> Downtrend, consider holding short or staying out

2. Clear Buy/Sell Signals

SignalConditionAction
BuyTrend changes from -1 to 1 (close breaks above upper band)Open long position
SellTrend changes from 1 to -1 (close breaks below lower band)Close long or open short

3. Dynamic Stop-Loss Level

The SuperTrend line itself serves as the suggested stop-loss. In an uptrend, the lower band (green line) continuously rises without retreating, naturally forming an ascending stop-loss level.

4. Volatility Adaptation

Because it is based on ATR, SuperTrend automatically widens the band during high-volatility periods and narrows it during low-volatility periods, avoiding the mismatch of fixed stop-loss distances across different volatility environments.

Note

SuperTrend performs excellently in trending markets but produces frequent false signals during extended sideways consolidation. Consider combining it with ADX or other trend strength indicators to filter signals.

V. Advantages, Disadvantages, and Use Cases

Advantages

  1. Minimal parameters: Only 2 parameters, small tuning space, less prone to overfitting
  2. Clear signals: Color/position changes directly indicate buy or sell, no subjective judgment needed
  3. Volatility adaptive: ATR foundation enables reasonable performance across different volatility environments
  4. Anti-rollback mechanism: Final bands only move in the favorable direction, never retreating to widen the stop
  5. Computationally efficient: Simple algorithm, suitable for real-time calculations and high-frequency backtesting

Disadvantages

  1. Many false signals in ranging markets: Repeated reversals in sideways ranges produce consecutive small losses
  2. Lagging: Signals are delayed at the beginning of trend reversals, missing part of the move
  3. Cannot measure trend strength: Only provides direction, does not quantify trend intensity
  4. Gap sensitivity: Large gaps can instantly change the trend determination

Use Cases

ScenarioSuitabilityNotes
One-directional trending marketsHighReliable signals with effective trailing stops
Intraday trading (5min/15min)HighSuitable for intraday swing trading
Daily trend tradingHighEffectively filters daily timeframe noise
Narrow range consolidationLowFrequent reversals cause consecutive losses
Extreme events (black swans)LowATR may not adapt quickly enough to sudden volatility

Comparison with Similar Indicators

DimensionSuperTrendParabolic SARMoving AverageIchimoku
Number of Parameters2214
Volatility AdaptationYes (ATR)Yes (AF acceleration)NoNo
Stop-Loss FunctionBuilt-inBuilt-inRequires additional designCloud provides reference
Signal FrequencyMediumRelatively highRelatively lowMedium
Ranging Market PerformancePoorPoorMediumPoor
Visual ComplexitySimpleSimpleSimpleComplex
Best Practices
  • Combine with ADX: Enable SuperTrend signals when ADX > 25, pause trading when ADX < 20
  • Multi-timeframe analysis: Confirm trend direction on higher timeframes, use SuperTrend on lower timeframes for entry
  • Use multiple parameter sets (e.g., observe multiplier=2 and multiplier=3 simultaneously), enter when both signals agree
  • Include slippage and commissions in backtesting, as reversal signals can be frequent