◈   ∿ algotrading · Intermediate

Supertrend in Python: Build Crypto Trading Signals

Learn to code, backtest, and automate the Supertrend indicator in Python for crypto markets. Practical examples using Binance data with full working code.

Uncle Solieditor · voc · 18.05.2026 ·views 4
◈   Contents
  1. → What Is the Supertrend Indicator?
  2. → Setting Up Your Python Environment
  3. → Calculating Supertrend in Python Step by Step
  4. → Backtesting Supertrend on Crypto Markets
  5. → Running Supertrend Signals on Live Markets
  6. → Tuning Supertrend Parameters for Crypto
  7. → Frequently Asked Questions
  8. → Conclusion

The Supertrend indicator flips a lot of traders from losing to consistently profitable — not because it's magic, but because it cuts through market noise and gives you a clear, unambiguous signal: buy or sell. When you code it in Python and run it against real crypto data from Binance or Bybit, something clicks. You stop second-guessing candles and start trusting a system. This guide walks you through building that system from scratch.

What Is the Supertrend Indicator?

Supertrend is a trend-following indicator built on top of ATR — Average True Range. ATR measures how much an asset moves on average, accounting for gaps. Supertrend uses that volatility measurement to draw a dynamic band around price action. When price closes above the band, you get a green signal (bullish). When it closes below, you get red (bearish). The band flips sides when the trend reverses.

Think of it like a moving floor and ceiling. During a bull run, the Supertrend line acts as a floor beneath price — as long as price stays above it, you're in the trend. The moment price crashes through that floor, the line snaps to the ceiling and the signal flips to bearish. It's essentially an adaptive trailing stop that also tells you direction.

Key Takeaway: Supertrend doesn't predict where price is going — it tells you which side of the trend you're currently on. It's a confirmation tool, not a crystal ball.

Setting Up Your Python Environment

You'll need three libraries: ccxt for fetching OHLCV data from exchanges like Binance or OKX, pandas for data manipulation, and numpy for math. If you're running backtests, pandas-ta gives you a ready-made Supertrend function so you don't have to reinvent the wheel.

pip install ccxt pandas numpy pandas-ta

Once installed, pull historical data from Binance. CCXT makes this one function call regardless of which exchange you target — switching from Binance to Bybit is literally changing one word in your code.

import ccxt
import pandas as pd

def fetch_ohlcv(symbol='BTC/USDT', timeframe='1h', limit=500, exchange_id='binance'):
    exchange = getattr(ccxt, exchange_id)()
    ohlcv = exchange.fetch_ohlcv(symbol, timeframe, limit=limit)
    df = pd.DataFrame(ohlcv, columns=['timestamp', 'open', 'high', 'low', 'close', 'volume'])
    df['timestamp'] = pd.to_datetime(df['timestamp'], unit='ms')
    df.set_index('timestamp', inplace=True)
    return df

# Fetch 500 hourly candles for BTC/USDT from Binance
df = fetch_ohlcv('BTC/USDT', '1h', 500, 'binance')
print(df.tail())

Calculating Supertrend in Python Step by Step

You have two options: use pandas-ta for a one-liner, or implement it manually for full control. Both are valid — the manual version is better if you want to understand what's happening under the hood or need to tune the calculation for speed in a live bot.

The pandas-ta approach is the fastest way to get running:

import pandas_ta as ta

# period=10, multiplier=3.0 are the classic defaults
df.ta.supertrend(length=10, multiplier=3.0, append=True)

# pandas-ta adds these columns:
# SUPERT_10_3.0       — the actual band value
# SUPERTd_10_3.0      — direction: 1 = bullish, -1 = bearish
# SUPERTl_10_3.0      — long band
# SUPERTs_10_3.0      — short band

df['signal'] = df['SUPERTd_10_3.0'].map({1: 'BUY', -1: 'SELL'})
print(df[['close', 'SUPERT_10_3.0', 'signal']].tail(10))

If you prefer to build it manually — useful when you're deploying to a server without pandas-ta or need exact control over ATR smoothing:

import numpy as np

def supertrend(df, period=10, multiplier=3.0):
    hl2 = (df['high'] + df['low']) / 2

    # True Range
    prev_close = df['close'].shift(1)
    tr = pd.concat([
        df['high'] - df['low'],
        (df['high'] - prev_close).abs(),
        (df['low'] - prev_close).abs()
    ], axis=1).max(axis=1)

    # Wilder's ATR (RMA)
    atr = tr.ewm(alpha=1/period, adjust=False).mean()

    upper = hl2 + multiplier * atr
    lower = hl2 - multiplier * atr

    supertrend_vals = pd.Series(index=df.index, dtype=float)
    direction = pd.Series(index=df.index, dtype=int)

    for i in range(1, len(df)):
        # Adjust upper band
        if upper.iloc[i] < upper.iloc[i-1] or df['close'].iloc[i-1] > upper.iloc[i-1]:
            final_upper = upper.iloc[i]
        else:
            final_upper = upper.iloc[i-1]

        # Adjust lower band
        if lower.iloc[i] > lower.iloc[i-1] or df['close'].iloc[i-1] < lower.iloc[i-1]:
            final_lower = lower.iloc[i]
        else:
            final_lower = lower.iloc[i-1]

        upper.iloc[i] = final_upper
        lower.iloc[i] = final_lower

        # Direction
        if direction.iloc[i-1] == -1:  # Was bearish
            direction.iloc[i] = 1 if df['close'].iloc[i] > final_upper else -1
        else:  # Was bullish
            direction.iloc[i] = -1 if df['close'].iloc[i] < final_lower else 1

        supertrend_vals.iloc[i] = final_lower if direction.iloc[i] == 1 else final_upper

    df['supertrend'] = supertrend_vals
    df['direction'] = direction
    df['signal'] = direction.map({1: 'BUY', -1: 'SELL'})
    return df

df = supertrend(df)
Key Takeaway: The manual implementation uses Wilder's smoothing (EWM with alpha=1/period) for ATR — this matches TradingView's Supertrend exactly. If your signals don't match TradingView, ATR smoothing is usually the culprit.

Backtesting Supertrend on Crypto Markets

Before trusting any indicator with real money, run it through history. A basic backtest loops through your signal column, enters on BUY, exits on SELL, and tracks the result. This isn't meant to be production-grade — it's meant to tell you whether the indicator has any edge on your chosen pair and timeframe.

def backtest(df, initial_capital=10000):
    capital = initial_capital
    position = 0
    entry_price = 0
    trades = []

    for i in range(1, len(df)):
        signal = df['signal'].iloc[i]
        price = df['close'].iloc[i]
        prev_signal = df['signal'].iloc[i-1]

        # Enter long on BUY signal
        if signal == 'BUY' and prev_signal == 'SELL' and position == 0:
            position = capital / price
            entry_price = price

        # Exit on SELL signal
        elif signal == 'SELL' and prev_signal == 'BUY' and position > 0:
            exit_value = position * price
            pnl = exit_value - capital
            trades.append({
                'entry': entry_price,
                'exit': price,
                'pnl': pnl,
                'pnl_pct': (price / entry_price - 1) * 100
            })
            capital = exit_value
            position = 0

    results = pd.DataFrame(trades)
    if not results.empty:
        print(f"Total trades: {len(results)}")
        print(f"Win rate: {(results['pnl'] > 0).mean():.1%}")
        print(f"Total return: {(capital / initial_capital - 1):.1%}")
        print(f"Avg trade: {results['pnl_pct'].mean():.2f}%")
    return results, capital

trades, final_capital = backtest(df)

When you run this on BTC/USDT 1h data from Binance, typical results show 45-60% win rate with a positive expectancy — Supertrend catches the big moves even if it whipsaws on choppy days. ETH/USDT tends to behave similarly. Altcoins with thinner liquidity (available on Gate.io and KuCoin) often need a higher multiplier to reduce noise.

Running Supertrend Signals on Live Markets

Once you've backtested and found settings you're comfortable with, the live version is straightforward: fetch the latest candles every hour (or whatever your timeframe is), recalculate Supertrend, and check if the last signal changed. If it flipped from SELL to BUY — that's your entry trigger.

import time

def run_live(symbol='ETH/USDT', timeframe='1h', exchange_id='bybit'):
    print(f"Monitoring {symbol} on {exchange_id}...")
    last_signal = None

    while True:
        df = fetch_ohlcv(symbol, timeframe, 200, exchange_id)
        df = supertrend(df)
        current_signal = df['signal'].iloc[-1]

        if current_signal != last_signal:
            print(f"[SIGNAL CHANGE] {df.index[-1]} — {last_signal} → {current_signal}")
            print(f"Price: {df['close'].iloc[-1]:.2f}")
            last_signal = current_signal

        # Sleep until next candle close (3600s for 1h)
        time.sleep(3600)

run_live('ETH/USDT', '1h', 'bybit')

On Binance you can access most major pairs with tight spreads and reliable API uptime, making it the default choice for BTC and ETH bots. Bybit is strong for perpetual futures if you want to trade long and short signals directly. OKX is worth considering for its unified margin account which simplifies capital allocation across multiple Supertrend bots running simultaneously. If you want pre-built signals without running your own Python stack, VoiceOfChain provides real-time crypto trading signals including trend-based alerts — useful for confirming your bot's signals against broader market data.

Warning: Never run a live bot without a stop-loss or position size limit. Supertrend can stay wrong for multiple candles during choppy, sideways markets — size accordingly.

Tuning Supertrend Parameters for Crypto

The default period=10 and multiplier=3.0 are a starting point, not gospel. Crypto moves differently than traditional assets — higher volatility means you often need wider bands to avoid being whipsawed out of legitimate trends. Here's a practical reference for different use cases:

Supertrend parameter reference by trading style
StylePeriodMultiplierTimeframeBest For
Scalping72.05m / 15mBTC, ETH on Binance
Swing Trading103.01h / 4hMost major pairs
Position Trading144.01DBTC, ETH long-term
High Volatility Alts104.0–5.01hAltcoins on KuCoin, Gate.io

The fastest way to find optimal parameters is a grid search — loop through combinations, run your backtest on each, and pick the highest Sharpe ratio rather than raw return. Higher return often comes with higher drawdown; Sharpe balances both.

Frequently Asked Questions

Is Supertrend reliable for crypto?
Supertrend performs well during trending markets, which crypto has plenty of. It struggles during sideways consolidation, generating false signals. The key is combining it with a volatility filter — skip signals when ATR is unusually low, since that often signals a ranging market rather than a genuine trend.
What's the best timeframe for Supertrend in crypto?
The 1h and 4h timeframes offer the best balance between signal frequency and reliability for most traders. Lower timeframes like 5m produce too many whipsaws in crypto's volatile conditions. Daily timeframes work well for position traders who aren't watching the market constantly.
How do I avoid false signals with Supertrend?
Add a second confirmation layer — volume spike, RSI above 50 for longs, or a longer-period Supertrend pointing the same direction. Many traders also skip signals that appear within the first few candles after a major news event, since volatility spikes can generate unreliable ATR readings.
Can I use Supertrend with CCXT on any exchange?
Yes, CCXT supports Binance, Bybit, OKX, Coinbase, Bitget, Gate.io, KuCoin, and over 100 more. The fetch_ohlcv call works identically across all of them — just change the exchange_id parameter. Some exchanges require API keys even for public data; Binance does not for historical OHLCV.
Does Supertrend repaint?
The Supertrend indicator can appear to repaint in real-time because the current candle's ATR and band values update tick by tick until the candle closes. Always calculate signals on closed candles — use limit=N+1 and drop the last row if your timeframe hasn't closed yet. This is a common bug in live bots.
How is Supertrend different from Bollinger Bands?
Both use ATR or standard deviation to create bands, but Bollinger Bands measure mean reversion — price touching the outer band is a signal to reverse. Supertrend is the opposite: it's a trend-following tool where you trade in the direction of the breakout. They're philosophically different and shouldn't be confused.

Conclusion

Supertrend in Python is one of the most accessible ways to build a systematic crypto trading approach. You fetch data with CCXT from exchanges like Binance or Bybit, calculate the indicator with pandas-ta or a manual implementation, backtest it against real history, and then run it live with a simple polling loop. The indicator won't make you rich by itself — no indicator does. But it gives you a clear framework: a rule-based system that removes emotion and forces consistency. Start with BTC/USDT on the 1h timeframe, validate your backtest results, keep position sizes small, and iterate. That's the actual edge — not the indicator, but the discipline of following it.

◈   more on this topic
⌘ api Kraken API Documentation for Crypto Traders: Essentials and Examples ◉ basics Mastering the ccxt library documentation for crypto traders