← Back to Blog
STRATEGY

Supertrend Strategy: ATR-Based Trend Following on Crypto Perpetuals

May 26, 2026 · 6 min read · LMEX.AI

Supertrend is one of the cleanest trend-following indicators available. It's based on Average True Range, produces a single line that either flips green (uptrend) or red (downtrend), and avoids most of the ambiguity that plagues older indicators like MACD. The downside: it can lag, and naive implementations get whipsawed in ranges just like everything else.


This article walks through what Supertrend is, how to implement it for crypto perpetuals, and the additions that make it work in practice.


What Supertrend does


Supertrend tracks the price using an offset based on volatility:


  • In an uptrend, the line sits below price by a multiple of ATR
  • In a downtrend, the line sits above price by a multiple of ATR
  • When price crosses through the line, the trend flips

  • The two parameters:

  • **ATR period**: typically 10 or 14
  • **ATR multiplier**: typically 2 or 3

  • A larger multiplier means the line is further from price — fewer trend flips but later signals. A smaller multiplier means closer line — more flips but earlier signals. The standard (10, 3) is a reasonable starting point.


    How Supertrend differs from moving averages


    Moving averages smooth price by averaging. Supertrend tracks price more aggressively but uses ATR to bound the gap. The result is a line that:


  • Stays close to price during trends
  • Doesn't whip back and forth in volatile ranges (because the ATR adjusts to volatility)
  • Flips cleanly when momentum changes

  • Compared to EMA crossover, Supertrend produces fewer false signals but slightly later entries. Compared to MACD, it's simpler and more visually intuitive.


    Python implementation


    A working Supertrend calculation:


    import pandas as pd
    import numpy as np
    import ccxt
    
    exchange = ccxt.lmex()
    
    def calculate_atr(df, period=14):
        high_low = df['h'] - df['l']
        high_close = abs(df['h'] - df['c'].shift())
        low_close = abs(df['l'] - df['c'].shift())
        tr = pd.concat([high_low, high_close, low_close], axis=1).max(axis=1)
        return tr.ewm(span=period).mean()
    
    def calculate_supertrend(df, period=10, multiplier=3):
        df['atr'] = calculate_atr(df, period)
        hl2 = (df['h'] + df['l']) / 2
        
        df['upper_band'] = hl2 + multiplier * df['atr']
        df['lower_band'] = hl2 - multiplier * df['atr']
        
        df['supertrend'] = 0.0
        df['direction'] = 1  # 1 = uptrend, -1 = downtrend
        
        for i in range(1, len(df)):
            prev_st = df['supertrend'].iloc[i-1]
            prev_dir = df['direction'].iloc[i-1]
            close = df['c'].iloc[i]
            
            # Adjust bands
            if df['upper_band'].iloc[i] < prev_st or df['c'].iloc[i-1] > prev_st:
                upper = df['upper_band'].iloc[i]
            else:
                upper = prev_st
            
            if df['lower_band'].iloc[i] > prev_st or df['c'].iloc[i-1] < prev_st:
                lower = df['lower_band'].iloc[i]
            else:
                lower = prev_st
            
            # Determine direction
            if prev_dir == 1:
                if close < lower:
                    direction = -1
                    st = upper
                else:
                    direction = 1
                    st = lower
            else:
                if close > upper:
                    direction = 1
                    st = lower
                else:
                    direction = -1
                    st = upper
            
            df.iloc[i, df.columns.get_loc('supertrend')] = st
            df.iloc[i, df.columns.get_loc('direction')] = direction
        
        return df
    
    # Usage
    candles = exchange.fetch_ohlcv('BTC-PERP', '1h', limit=500)
    df = pd.DataFrame(candles, columns=['ts', 'o', 'h', 'l', 'c', 'v'])
    df = calculate_supertrend(df, period=10, multiplier=3)
    
    # Latest signal
    last_direction = df['direction'].iloc[-1]
    print(f"Current trend: {'UP' if last_direction == 1 else 'DOWN'}")

    This calculates Supertrend and outputs the current direction. The actual trading logic adds entries on direction changes and exits on opposite signals.


    Basic strategy


    The simplest Supertrend strategy:

  • Direction changes from -1 to 1: go long
  • Direction changes from 1 to -1: go short (or close long)

  • On its own, this produces too many trades in ranging markets. The signal is too quick to flip back and forth.


    What works: Supertrend with confirmation


    Adding confirmation filters reduces whipsaws significantly:


    **Higher-timeframe direction.** Only take long signals when daily Supertrend is in uptrend. Only take shorts when daily Supertrend is in downtrend. Same indicator, multiple timeframes, used as filter.


    **Volume confirmation.** Require volume on the trend-flip candle to be above average. Genuine trend changes usually involve increased volume.


    **ADX threshold.** Only take signals when ADX > 20 (some trend exists). Filters out ranging markets where Supertrend isn't reliable.


    A more practical implementation:


    def supertrend_with_filters(df_1h, df_daily):
        df_1h = calculate_supertrend(df_1h, period=10, multiplier=3)
        df_daily = calculate_supertrend(df_daily, period=10, multiplier=3)
        
        # Map daily direction to 1h timestamps
        df_1h['daily_dir'] = df_1h['ts'].apply(
            lambda t: df_daily[df_daily['ts'] <= t]['direction'].iloc[-1]
        )
        
        # Calculate ADX for filter
        df_1h = calculate_adx(df_1h)
        
        df_1h['signal'] = 0
        long_setup = (
            (df_1h['direction'] == 1) & 
            (df_1h['direction'].shift() == -1) &
            (df_1h['daily_dir'] == 1) &
            (df_1h['adx'] > 20)
        )
        short_setup = (
            (df_1h['direction'] == -1) & 
            (df_1h['direction'].shift() == 1) &
            (df_1h['daily_dir'] == -1) &
            (df_1h['adx'] > 20)
        )
        df_1h.loc[long_setup, 'signal'] = 1
        df_1h.loc[short_setup, 'signal'] = -1
        return df_1h

    This produces 70-80% fewer signals than naive Supertrend, with higher win rate per signal.


    Parameter tuning


    The default (10, 3) is conservative. Variations to consider:


  • **(7, 2)**: faster, more signals, more noise. Suitable for very liquid markets and shorter holds.
  • **(14, 3)**: standard.
  • **(14, 4)**: slower, fewer signals, longer holds.
  • **(21, 5)**: very slow, identifies major regime changes only.

  • For crypto on hourly bars, (10, 3) or (14, 3) tend to be optimal. For 4-hour bars, (14, 3) works well. For daily bars, (10, 2.5) or (14, 3) for catching longer trends.


    Use walk-forward analysis to validate parameter choices. If parameters jump significantly between optimization windows, the strategy is overfit.


    What doesn't work


    A few common Supertrend pitfalls:


    **Reducing the multiplier below 2.** Tighter Supertrend produces too many false signals. The math doesn't work below 2× ATR.


    **Trading every direction flip.** Without filters, this is a losing strategy in most markets. Always combine with at least one confirmation.


    **Using Supertrend as a stop-loss.** Tempting, since the Supertrend line is conveniently below price in uptrends. But it doesn't adapt to your specific entry — you can be stopped out repeatedly even on winning trends.


    Frequently Asked Questions


    Q: What timeframe works best for Supertrend?

    4-hour and daily for swing trading. 1-hour for active trading. Below 1-hour, Supertrend gets whipsawed by noise.


    Q: How does Supertrend compare to a trailing stop?

    Similar in concept (both adapt to volatility) but different in execution. Supertrend gives discrete signals when trend flips; trailing stops give continuous risk control. They complement each other.


    Q: Can I run Supertrend on multiple pairs simultaneously?

    Yes, and recommended for diversification. Different pairs will be in different trends at any given time. A portfolio of 5-10 markets running Supertrend smooths the equity curve.


    Q: Is Supertrend better than EMA crossover?

    It's different, not strictly better. Supertrend tends to give cleaner signals; EMA crossover has more academic study. Both work; pick one and stick with it.


    Related Articles


    → EMA Crossover: A Complete Guide for Crypto Perpetuals
    → Walk-Forward Optimization: The Only Backtest Method That Survives Reality
    → Backtesting Your LMEX Trading Bot in Python: A Practical Guide
    ← All ArticlesBuild a Bot →