Strategy · Pine Script v6 · On the chart

SuperTrend AI Strategy Adaptive

by kanylbullen· code credited to DefinedEdge

A Supertrend strategy drawn on the price chart whose multiplier can adapt to the detected market regime using ADX.

View on GitHub

GitHub stars1on the repository
Pine versionv6current
Lines of code355
Settings28inputs
LicenceNone statedfile: MPL-2.0
Last update7 days ago22 Oct 2026

Add It to Your TradingView Chart

  1. 1Copy the scriptPress Copy script above, or the copy button on the code below.
  2. 2Open the Pine EditorOpen a TradingView chart and choose Pine Editor at the bottom of the screen.
  3. 3Paste over the templateCreate a new strategy, select all of the template text and paste. Press Save and give it a name.
  4. 4Add it to the chartPress Add to chart. The trades and results appear in the Strategy Tester tab; adjust the settings with the gear icon.

Source Code

355 lines of Pine Script v6 from tv-source/supertrend.pine, published under MPL-2.0 (file header). Keep the author's credit and licence lines when you reuse it.

supertrend.pine
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © DefinedEdge

//@version=6
strategy("SuperTrend AI Strategy [Adaptive]", "ST AI Strategy ◈",
     overlay         = true,
     initial_capital  = 10000,
     default_qty_type = strategy.percent_of_equity,
     default_qty_value= 80,
     commission_type  = strategy.commission.percent,
     commission_value = 0.06,
     slippage         = 2,
     pyramiding       = 0,
     calc_on_every_tick = false,
     max_labels_count = 500)

// ============================================================================
// INPUTS
// ============================================================================

// --- SuperTrend Core ---
GRP_ST  = "◈ SuperTrend"
i_atLen = input.int(10,    "ATR Length",        minval=1, maxval=50, group=GRP_ST)
i_bMult = input.float(3.0, "Base Multiplier",   minval=0.5, maxval=10.0, step=0.1, group=GRP_ST)
i_src   = input.source(hl2, "Source",           group=GRP_ST)

// --- Regime Detection ---
GRP_REG  = "◈ Regime Detection"
i_regLen = input.int(40,    "Regime Lookback",   minval=10, maxval=100, group=GRP_REG)
i_adxLen = input.int(14,    "ADX Length",        minval=5,  maxval=50,  group=GRP_REG)
i_adxThr = input.float(20,  "ADX Trend Threshold", minval=10, maxval=40, step=1, group=GRP_REG)
i_adapt  = input.bool(true, "Adaptive Multiplier", group=GRP_REG)

// --- AI Scoring ---
GRP_AI     = "◈ AI Engine"
i_trendLen = input.int(50,  "Trend EMA Length",  minval=10, maxval=200, group=GRP_AI)
i_volLen   = input.int(20,  "Volume MA Length",   minval=5,  maxval=50, group=GRP_AI)
i_minSc    = input.int(65,  "Min Signal Score",   minval=0,  maxval=90, group=GRP_AI, tooltip="Only enter trades when the AI score meets this threshold.")

// --- Risk Management ---
GRP_RISK = "◈ Risk Management"
i_slMode = input.string("ATR", "Stop Loss Mode", options=["ATR", "Percent", "SuperTrend"], group=GRP_RISK, tooltip="ATR: dynamic SL based on volatility. Percent: fixed %. SuperTrend: exit on trend flip.")
i_slAtr  = input.float(6.0,  "SL ATR Multiplier", minval=0.5, maxval=8.0, step=0.1, group=GRP_RISK)
i_slPct  = input.float(3.0,  "SL Percent",        minval=0.5, maxval=10.0, step=0.1, group=GRP_RISK)
i_tpMode = input.string("RR", "Take Profit Mode", options=["RR", "Percent", "None"], group=GRP_RISK, tooltip="RR: risk/reward ratio based on SL distance. Percent: fixed %. None: hold until SL or flip.")
i_tpRR   = input.float(2.5,  "TP Risk:Reward",    minval=0.5, maxval=10.0, step=0.1, group=GRP_RISK)
i_tpPct  = input.float(6.0,  "TP Percent",        minval=0.5, maxval=20.0, step=0.1, group=GRP_RISK)
i_trail  = input.bool(false, "Trailing Stop",     group=GRP_RISK, tooltip="When enabled, SL trails in the direction of the trade after entry.")
i_trailAtr = input.float(2.5, "Trail ATR Mult",   minval=0.5, maxval=8.0, step=0.1, group=GRP_RISK)

// --- Filters ---
GRP_FLT  = "◈ Trade Filters"
i_trendF = input.bool(true,  "EMA Trend Filter",  group=GRP_FLT, tooltip="Only take longs above EMA, shorts below EMA.")
i_regF   = input.bool(true,  "Skip Ranging",      group=GRP_FLT, tooltip="Skip entries during ranging regime. Reduces whipsaws.")
i_volF   = input.bool(true,  "Volume Filter",      group=GRP_FLT, tooltip="Only enter if volume is above average.")
i_sigCD  = input.int(5,      "Cooldown (bars)",    minval=0, maxval=50, group=GRP_FLT)

// --- Backtest Window ---
GRP_BT   = "◈ Backtest"
i_btFrom = input.time(timestamp("2015-01-01"), "From", group=GRP_BT)
i_btTo   = input.time(timestamp("2030-01-01"), "To",   group=GRP_BT)
bool inWindow = time >= i_btFrom and time <= i_btTo

// --- Visuals ---
GRP_VIS  = "◈ Visuals"
i_sGlow  = input.bool(true,  "Band Glow Effect",    group=GRP_VIS)
i_sRegBg = input.bool(true,  "Regime Background",   group=GRP_VIS)


// --- Colors ---
GRP_COL  = "◈ Colors"
i_cBull  = input.color(color.new(#089981, 0), "Bull",  inline="c1", group=GRP_COL)
i_cBear  = input.color(color.new(#f23645, 0), "Bear",  inline="c1", group=GRP_COL)

// ============================================================================
// CORE CALCULATIONS
// ============================================================================

int n = bar_index
float atr = ta.atr(i_atLen)
float safeAtr = nz(atr, 0.001)

// ── Regime Detection ──
float atrMa    = ta.sma(atr, i_regLen)
float atrRatio = atrMa > 0 ? atr / atrMa : 1.0

// ADX
float upMove   = high - high[1]
float dnMove   = low[1] - low
float plusDM    = upMove > dnMove and upMove > 0 ? upMove : 0
float minusDM  = dnMove > upMove and dnMove > 0 ? dnMove : 0
float trueR    = ta.tr
float smoothTR = ta.rma(trueR, i_adxLen)
float smoothPD = ta.rma(plusDM, i_adxLen)
float smoothND = ta.rma(minusDM, i_adxLen)
float plusDI    = smoothTR > 0 ? 100 * smoothPD / smoothTR : 0
float minusDI  = smoothTR > 0 ? 100 * smoothND / smoothTR : 0
float diSum    = plusDI + minusDI
float dx       = diSum > 0 ? 100 * math.abs(plusDI - minusDI) / diSum : 0
float adx      = ta.rma(dx, i_adxLen)

var int regime = 1
if atrRatio > 1.4
    regime := 2
else if adx < i_adxThr and atrRatio < 0.9
    regime := 0
else
    regime := 1

// ── Adaptive Multiplier ──
float adaptMult = i_bMult
if i_adapt
    if regime == 2
        adaptMult := i_bMult * (1.0 + (atrRatio - 1.0) * 0.4)
    else if regime == 0
        adaptMult := i_bMult * 0.85
adaptMult := math.max(math.min(adaptMult, i_bMult * 2.0), i_bMult * 0.5)

// ── SuperTrend ──
var float stBand  = na
var int   stDir   = 1

float upperBase = i_src + adaptMult * atr
float lowerBase = i_src - adaptMult * atr
float prevBand  = nz(stBand[1], stDir == 1 ? lowerBase : upperBase)

if stDir == 1
    stBand := math.max(lowerBase, prevBand)
    if close < stBand
        stDir  := -1
        stBand := upperBase
else
    stBand := math.min(upperBase, prevBand)
    if close > stBand
        stDir  := 1
        stBand := lowerBase

bool trendFlip = stDir != stDir[1]

// ── Trend EMA ──
float trendMa = ta.ema(close, i_trendLen)
bool  trendUp = close > trendMa
bool  trendDn = close < trendMa

// ── Volume ──
float volMa = ta.sma(volume, i_volLen)

// ============================================================================
// AI SIGNAL SCORING
// ============================================================================

scoreSignal(bool isBull) =>
    float score = 0

    // Factor 1: Volume surge (0-20)
    float vRat = volMa > 0 ? volume / volMa : 1.0
    score += vRat >= 2.5 ? 20 : vRat >= 1.5 ? 14 : vRat >= 1.0 ? 8 : 3

    // Factor 2: Displacement beyond band (0-25)
    float disp = isBull ? (close - stBand) : (stBand - close)
    float dispAtr = safeAtr > 0 ? disp / safeAtr : 0
    score += dispAtr >= 1.5 ? 25 : dispAtr >= 0.8 ? 18 : dispAtr >= 0.3 ? 12 : dispAtr > 0 ? 5 : 0

    // Factor 3: EMA trend alignment (0-20)
    bool aligned = (isBull and trendUp) or (not isBull and trendDn)
    float emaDist = math.abs(close - trendMa) / safeAtr
    score += aligned and emaDist > 0.5 ? 20 : aligned ? 14 : emaDist < 0.3 ? 8 : 2

    // Factor 4: Regime quality (0-15)
    score += regime == 1 ? 15 : regime == 2 ? 8 : 3

    // Factor 5: Band distance before flip (0-20)
    float prevDist = not na(stBand[1]) ? math.abs(close[1] - stBand[1]) / safeAtr : 0
    score += prevDist >= 2.0 ? 20 : prevDist >= 1.0 ? 14 : prevDist >= 0.5 ? 8 : 3

    int(math.min(math.round(score), 100))

// ============================================================================
// TRADE LOGIC
// ============================================================================

var int   lastEntryBar  = 0
var float entryPrice    = 0.0
var float slPrice       = 0.0
var float tpPrice       = 0.0
var int   lastSigScore  = 0
var int   lastSigDir    = 0
var bool  lastSigBright = false

bool longEntry  = false
bool shortEntry = false
int  sigScore   = 0

// Cooldown check
bool cdOk = (n - lastEntryBar) > i_sigCD

if trendFlip and inWindow and cdOk and barstate.isconfirmed
    if stDir == 1
        sigScore := scoreSignal(true)
        // Apply filters
        bool passScore = sigScore >= i_minSc
        bool passTrend = not i_trendF or trendUp
        bool passReg   = not i_regF or regime != 0
        bool passVol   = not i_volF or (volume > volMa)

        if passScore and passTrend and passReg and passVol
            longEntry := true

    else
        sigScore := scoreSignal(false)
        bool passScore = sigScore >= i_minSc
        bool passTrend = not i_trendF or trendDn
        bool passReg   = not i_regF or regime != 0
        bool passVol   = not i_volF or (volume > volMa)

        if passScore and passTrend and passReg and passVol
            shortEntry := true

// ── Calculate SL/TP Levels ──
float slDist = 0.0
if i_slMode == "ATR"
    slDist := atr * i_slAtr
else if i_slMode == "Percent"
    slDist := close * i_slPct / 100
else // SuperTrend mode
    slDist := math.abs(close - stBand)

float tpDist = 0.0
if i_tpMode == "RR"
    tpDist := slDist * i_tpRR
else if i_tpMode == "Percent"
    tpDist := close * i_tpPct / 100

// ── Execute Entries ──
if longEntry
    // Close any existing short
    if strategy.position_size < 0
        strategy.close("Short")

    entryPrice := close
    slPrice    := close - slDist
    tpPrice    := i_tpMode != "None" ? close + tpDist : na

    strategy.entry("Long", strategy.long)

    if not na(slPrice) and i_tpMode != "None" and not na(tpPrice)
        strategy.exit("Long Exit", "Long", stop=slPrice, limit=tpPrice,
             trail_points = i_trail ? slDist / syminfo.mintick : na,
             trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
    else if not na(slPrice)
        strategy.exit("Long SL", "Long", stop=slPrice,
             trail_points = i_trail ? slDist / syminfo.mintick : na,
             trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)

    lastEntryBar  := n
    lastSigScore  := sigScore
    lastSigDir    := 1
    lastSigBright := sigScore >= 70

if shortEntry
    // Close any existing long
    if strategy.position_size > 0
        strategy.close("Long")

    entryPrice := close
    slPrice    := close + slDist
    tpPrice    := i_tpMode != "None" ? close - tpDist : na

    strategy.entry("Short", strategy.short)

    if not na(slPrice) and i_tpMode != "None" and not na(tpPrice)
        strategy.exit("Short Exit", "Short", stop=slPrice, limit=tpPrice,
             trail_points = i_trail ? slDist / syminfo.mintick : na,
             trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)
    else if not na(slPrice)
        strategy.exit("Short SL", "Short", stop=slPrice,
             trail_points = i_trail ? slDist / syminfo.mintick : na,
             trail_offset = i_trail ? (atr * i_trailAtr) / syminfo.mintick : na)

    lastEntryBar  := n
    lastSigScore  := sigScore
    lastSigDir    := -1
    lastSigBright := sigScore >= 70

// ── SuperTrend Flip Exit (if SL mode is SuperTrend) ──
if i_slMode == "SuperTrend" and trendFlip
    if strategy.position_size > 0 and stDir == -1
        strategy.close("Long", comment="ST Flip")
    if strategy.position_size < 0 and stDir == 1
        strategy.close("Short", comment="ST Flip")

// ============================================================================
// VISUALS
// ============================================================================

// ── Band Color ──
color bandCore  = stDir == 1 ? i_cBull : i_cBear
color bandColor = regime == 2 ? color.new(#ffab00, 0) : regime == 0 ? color.new(#78909c, 20) : bandCore

// ── Glow ──
plot(i_sGlow ? stBand : na, "Glow Outer", color=color.new(bandColor, 85), linewidth=6, style=plot.style_linebr)
plot(i_sGlow ? stBand : na, "Glow Mid",   color=color.new(bandColor, 70), linewidth=4, style=plot.style_linebr)

// ── Band ──
plot(regime != 0 ? stBand : na, "Band (Solid)",   color=bandColor, linewidth=2, style=plot.style_linebr)
plot(regime == 0 ? stBand : na, "Band (Ranging)",  color=bandColor, linewidth=2, style=plot.style_linebr, linestyle=plot.linestyle_dotted)

// ── Flip Dot ──
plot(trendFlip ? stBand : na, "Flip Dot", color=bandCore, style=plot.style_circles, linewidth=5, join=false)

// ── Regime Background ──
bgcolor(i_sRegBg and regime == 2 ? color.new(#ffab00, 95) : na, title="Volatile BG")
bgcolor(i_sRegBg and regime == 0 ? color.new(#78909c, 96) : na, title="Ranging BG")

// ── Trend EMA ──
plot(trendMa, "Trend EMA", color=color.new(trendUp ? i_cBull : i_cBear, 65), linewidth=1)

// ── Entry Labels ──
bool isBright = sigScore >= 70

if longEntry
    string ico = isBright ? "★" : "○"
    string txt = ico + " " + str.tostring(sigScore)
    color  css = isBright ? color.new(#00e676, 0) : color.new(#546e7a, 0)
    label.new(n, stBand, txt,
      color=color.new(css, isBright ? 0 : 50),
      textcolor=#ffffff, size=isBright ? size.small : size.tiny,
      style=label.style_label_up,
      tooltip="LONG | Score: " + str.tostring(sigScore) +
              "\nRegime: " + (regime == 1 ? "TRENDING" : regime == 2 ? "VOLATILE" : "RANGING") +
              "\nSL: " + str.tostring(math.round(slDist / close * 100, 2)) + "%" +
              "\nTP: " + (i_tpMode != "None" ? str.tostring(math.round(tpDist / close * 100, 2)) + "%" : "None"))

if shortEntry
    string ico = isBright ? "★" : "○"
    string txt = ico + " " + str.tostring(sigScore)
    color  css = isBright ? color.new(#ff5252, 0) : color.new(#546e7a, 0)
    label.new(n, stBand, txt,
      color=color.new(css, isBright ? 0 : 50),
      textcolor=#ffffff, size=isBright ? size.small : size.tiny,
      style=label.style_label_down,
      tooltip="SHORT | Score: " + str.tostring(sigScore) +
              "\nRegime: " + (regime == 1 ? "TRENDING" : regime == 2 ? "VOLATILE" : "RANGING") +
              "\nSL: " + str.tostring(math.round(slDist / close * 100, 2)) + "%" +
              "\nTP: " + (i_tpMode != "None" ? str.tostring(math.round(tpDist / close * 100, 2)) + "%" : "None"))

// ============================================================================
// HIDDEN PLOTS
// ============================================================================

plot(sigScore > 0 ? sigScore : na, "Signal Score", display=display.none)
plot(adaptMult,     "Adaptive Mult",  display=display.none)
plot(adx,           "ADX",            display=display.none)
plot(float(regime), "Regime",         display=display.none)
plot(float(stDir),  "Trend Direction", display=display.none)

Overview

Entries need a minimum signal score and can be filtered by a trend EMA, a skip-ranging rule, a volume filter and a bar cooldown. Stop loss can use ATR, percent or Supertrend flips. Take profit can use risk-reward, percent or none, with an optional ATR trailing stop and a backtest date window. Position size is a percentage of equity.

Details

Published by

kanylbullen on GitHub

Code credit

DefinedEdge, as written in the script's header

Type

Strategy, Pine Script v6

Draws

On the price chart

Category

Trend, Volatility & bands

Markets

Any symbol

Timeframes

Any timeframe

Risk Notes

No repainting, lookahead or stacked entries were found in its code or README. That says nothing about how well it works: test it first.

Settings

The inputs you can change from the gear icon on the chart. Defaults are the author's.

SettingTypeDefaultVariable
ATR Lengthint10i_atLen
Base Multiplierfloat3.0i_bMult
Sourcesourcehl2i_src
Regime Lookbackint40i_regLen
ADX Lengthint14i_adxLen
ADX Trend Thresholdfloat20i_adxThr
Adaptive Multiplierbooltruei_adapt
Trend EMA Lengthint50i_trendLen
Volume MA Lengthint20i_volLen
Min Signal Scoreint65i_minSc
Stop Loss ModestringATRi_slMode
SL ATR Multiplierfloat6.0i_slAtr
Show all 28 settings
SettingTypeDefaultVariable
SL Percentfloat3.0i_slPct
Take Profit ModestringRRi_tpMode
TP Risk:Rewardfloat2.5i_tpRR
TP Percentfloat6.0i_tpPct
Trailing Stopboolfalsei_trail
Trail ATR Multfloat2.5i_trailAtr
EMA Trend Filterbooltruei_trendF
Skip Rangingbooltruei_regF
Volume Filterbooltruei_volF
Cooldown (bars)int5i_sigCD
Fromtimetimestamp("2015-01-01")i_btFrom
Totimetimestamp("2030-01-01")i_btTo
Band Glow Effectbooltruei_sGlow
Regime Backgroundbooltruei_sRegBg
Bullcolorcolor.new(#089981, 0)i_cBull
Bearcolorcolor.new(#f23645, 0)i_cBear
Third-party code. ForexR did not write, test or endorse this script, and the summary above was generated automatically from its code and README. Indicators describe the past, and a strategy's backtest can look better than live trading, especially when a script repaints. Check it in the Strategy Tester and on a demo account before you rely on it.

Similar Pine Scripts

330 stars

This strategy calculates Bollinger Bands and Aroon oscillator values to identify mean-reversion opportunities. It enters a long position using full equity when the closing price crosses below the lower Bollinger Band while Aroon Up remains above a user-specifi

Strategy v5 Mean reversionVolatility & bands
Updated 2 months ago · None stated GitHub repository of Bollinger bands + Aroon [Alorse]
257 stars

This overlay strategy targets one-minute ES futures and plots volume-weighted moving-average bands from the open, scaled by a standard-deviation multiple, plus a slower band from ten-minute opens. A higher-timeframe exponential moving average can filter trades

Strategy v6 Moving averagesVolatility & bands
Updated 6 weeks ago · None stated GitHub repository of ES - Futures 1M No Repaint

STRG-BBForce

by harryguiacorn
219 stars

STRG-BBForce is a Bollinger Bands trend-following strategy. It calculates standard Bollinger Bands and tracks directional alignment across the upper, lower, and basis lines. When all three lines slope upward, it opens a long position and closes short positions

Strategy v5 TrendVolatility & bands
Updated 1 year ago · None stated GitHub repository of STRG-BBForce

Nasdaq Prop Firm Strategy

by TradersPost
218 stars

This strategy uses multiple VWAP anchors and a custom Lull indicator to generate buy and sell signals on the Nasdaq price chart. It plots the VWAP trend line and three VWAP anchors with customizable colors and mitigation methods. The Lull indicator produces si

Strategy v6 TrendSupport & resistance Repaints
Updated 3 months ago · None stated GitHub repository of Nasdaq Prop Firm Strategy

This strategy implements a single-layer perceptron machine learning model built from scratch to generate trading signals directly on the price chart. It calculates predictions based on sample size, threshold settings, and optional volatility or volume filters.

Strategy v5 AI / machine learningTrend
Updated 1 year ago · None stated GitHub repository of Machine Learning: Perceptron-Based Strategy [5] (v.3)
106 stars

This overlay strategy plots a two-timeframe Ichimoku setup on the price chart, with Tenkan, Kijun, Chikou, and Kumo from a base higher timeframe and an optional highest-timeframe cloud. It allows two entries in the same direction and uses ATR-based trailing st

Strategy v4 TrendVolatility & bands
Updated 2 years ago · GPL-3.0 GitHub repository of 2Tier Ichimoku Pyramiding [Takazudo]

More strategys

Trade Your Charts With a Regulated Broker

Compare brokers that connect to TradingView, with spreads, minimum deposits and leverage side by side.

Compare brokers