Automate a Supertrend Strategy with Alerts in Pine Script v6

Automate a Supertrend Strategy with Alerts in Pine Script v6

By HorizonAI Team · 14 min read · Intermediate

You've watched the Supertrend flip from red to green dozens of times. You've taken the trade manually, sometimes nailed it, sometimes missed the candle close by 30 seconds. The signal is sound. The execution is the problem.

This guide fixes that. You'll convert Supertrend from a passive visual indicator into a fully coded Pine Script v6 strategy with entries, exits, an ATR trailing stop, a higher-timeframe filter to cut false flips, and webhook-ready alert messages you can pipe directly into a broker API. Every code block runs. Every parameter is justified.

What You'll Learn

  • How Supertrend's ATR-based math actually works (and which parameters to change first)
  • Building a strategy() script from scratch, not just an indicator overlay
  • Entering and exiting on confirmed trend flips with strategy.entry and strategy.exit
  • Adding an ATR trailing stop that moves with price
  • Filtering noisy flips with a 200 EMA or higher-timeframe trend confirmation
  • Firing alertcondition() and alert() calls with JSON payloads for broker webhooks
  • Reading the Strategy Tester output to know if your setup is actually worth trading

How Supertrend's ATR Logic Works

Supertrend is a trend-following overlay built on two inputs: an ATR period (default 10) and a multiplier factor (default 3.0). The indicator calculates upper and lower bands around price:

  • Upper band = (high + low) / 2 + factor × ATR(period)
  • Lower band = (high + low) / 2 − factor × ATR(period)

When price closes above the upper band, the trend flips bullish and the lower band becomes the trailing support line. When price closes below the lower band, it flips bearish. The line you see on the chart is just whichever band is active.

The key insight: the multiplier controls sensitivity more than the ATR period does. A factor of 1.5 generates signals on almost every swing. A factor of 4.0 only catches major trend changes. For intraday scalping on the 15-minute chart, 10/2.0 works well. For swing trading on the daily, 10/3.0 or 14/3.5 is more appropriate.

Tip: Before automating anything, backtest at least three factor values on your specific instrument. Crypto pairs like BTC/USDT behave very differently from EUR/USD at the same settings.

Setting Up the Strategy Shell

The difference between an indicator() and a strategy() script is that the latter can place simulated orders and report P&L in the Strategy Tester. You lose nothing by switching — you can still plot everything.

Here's the base shell with Supertrend calculated natively:

//@version=6
strategy(
     title          = "Supertrend Automated Strategy",
     overlay        = true,
     initial_capital = 10000,
     default_qty_type = strategy.percent_of_equity,
     default_qty_value = 10,
     commission_type  = strategy.commission.percent,
     commission_value = 0.05,
     slippage         = 2
)

// ── Inputs ──────────────────────────────────────────────────────────────────
atrPeriod  = input.int(10,  "ATR Period",     minval = 1)
factor     = input.float(3.0, "Factor",       minval = 0.1, step = 0.1)
emaLength  = input.int(200, "EMA Filter Length", minval = 1)
useEmaFilter = input.bool(true, "Use EMA Trend Filter")

// ── Supertrend Calculation ───────────────────────────────────────────────────
[supertrend, direction] = ta.supertrend(factor, atrPeriod)

// direction = -1 → bullish (price above band), 1 → bearish
bullish = direction == -1
bearish = direction ==  1

// Detect flips
toBull = bullish and direction[1] == 1   // just flipped bullish
toBear = bearish and direction[1] == -1  // just flipped bearish

// ── EMA Trend Filter ────────────────────────────────────────────────────────
ema200 = ta.ema(close, emaLength)
aboveEma = close > ema200
belowEma = close < ema200

// ── Entry Conditions ────────────────────────────────────────────────────────
longCondition  = toBull and (not useEmaFilter or aboveEma)
shortCondition = toBear and (not useEmaFilter or belowEma)

// ── Strategy Orders ─────────────────────────────────────────────────────────
if longCondition
    strategy.entry("Long", strategy.long)

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

// ── Exit on Opposite Flip ────────────────────────────────────────────────────
if toBear
    strategy.close("Long")
if toBull
    strategy.close("Short")

// ── Plotting ────────────────────────────────────────────────────────────────
plot(supertrend, "Supertrend",
     color = bullish ? color.new(color.green, 0) : color.new(color.red, 0),
     linewidth = 2)

plot(ema200, "EMA 200", color = color.new(color.yellow, 40), linewidth = 1)

plotshape(longCondition,  "Buy Signal",  shape.labelup,   location.belowbar, color.green, text="L", size=size.small)
plotshape(shortCondition, "Sell Signal", shape.labeldown, location.abovebar, color.red,   text="S", size=size.small)

Notice commission_value = 0.05 and slippage = 2. These are realistic for a crypto exchange. Backtesting without friction produces fantasy numbers.

Adding an ATR Trailing Stop

Flip-based exits work, but they give back a lot of open profit when the market whipsaws before reversing. An ATR trailing stop locks in gains progressively.

The logic: once in a long, the stop sits at close - atrMultiplier × ATR. Each bar it can only move up, never down. For a short, it mirrors.

//@version=6
// (Add this block inside the strategy above, after the entry orders)

// ── ATR Trailing Stop ────────────────────────────────────────────────────────
atrStopMult  = input.float(1.5, "ATR Stop Multiplier", minval = 0.1, step = 0.1)
atrValue     = ta.atr(atrPeriod)

// Track the trailing stop level
var float longStop  = na
var float shortStop = na

if strategy.position_size > 0
    longStop := na(longStop[1]) ? close - atrStopMult * atrValue
                                 : math.max(longStop[1], close - atrStopMult * atrValue)
    strategy.exit("Long TS", "Long", stop = longStop)

if strategy.position_size < 0
    shortStop := na(shortStop[1]) ? close + atrStopMult * atrValue
                                  : math.min(shortStop[1], close + atrStopMult * atrValue)
    strategy.exit("Short TS", "Short", stop = shortStop)

// Reset stops when flat
if strategy.position_size == 0
    longStop  := na
    shortStop := na

// Plot stop levels
plot(strategy.position_size > 0 ? longStop  : na, "Long Stop",  color.orange, style=plot.style_linebr)
plot(strategy.position_size < 0 ? shortStop : na, "Short Stop", color.orange, style=plot.style_linebr)

The multiplier of 1.5× ATR is intentionally tighter than the Supertrend factor (3.0×). You want the trailing stop to protect profit on a sharp reversal, while the Supertrend flip handles the full trend exit. They serve different purposes.

Tip: On volatile assets, widen the stop multiplier to 2.0–2.5× to avoid getting stopped out on normal noise. On Forex majors, 1.0–1.5× is usually sufficient.

Filtering False Flips with EMA and Higher-Timeframe Confirmation

Supertrend's biggest weakness is choppy markets. When price oscillates in a range, the direction flips repeatedly and each one looks like a new trend. Two filters cut most of this noise.

Filter 1: 200 EMA Trend Bias

Already baked into the code above. Only take longs when price is above the 200 EMA, only take shorts below it. This single rule eliminates a large proportion of counter-trend whipsaws on trending instruments.

The 200 EMA is a natural fit here because it's slow enough to define the macro regime without repainting. If you're working on a 1-hour chart, the 200 EMA represents roughly 8 days of price action — a meaningful structural reference.

Filter 2: Higher-Timeframe Supertrend

For a more precise filter, request the Supertrend direction from a higher timeframe using request.security():

// ── Higher-Timeframe Filter ──────────────────────────────────────────────────
htfTimeframe = input.timeframe("D", "HTF Timeframe")

// Request HTF Supertrend direction
[htfST, htfDir] = request.security(
     syminfo.tickerid,
     htfTimeframe,
     ta.supertrend(factor, atrPeriod),
     lookahead = barmerge.lookahead_off
)

htfBullish = htfDir == -1
htfBearish = htfDir ==  1

// Update entry conditions to require HTF alignment
longCondition  := toBull and htfBullish and (not useEmaFilter or aboveEma)
shortCondition := toBear and htfBearish and (not useEmaFilter or belowEma)

If you're running the strategy on the 1-hour chart, set htfTimeframe to "D" (daily). The daily Supertrend must agree with the hourly flip before any order fires. This is the same multi-timeframe alignment principle used in the simple moving average crossover strategy — lower-timeframe signals filtered by higher-timeframe structure.

Important: Always use lookahead = barmerge.lookahead_off with request.security(). Using lookahead_on introduces future data into your backtest and produces results you'll never replicate live.

Wiring Up Alerts and Webhook Payloads

Alerts are where the strategy goes from "automated on paper" to actually automated. Pine Script has two alert mechanisms:

  • alertcondition() — creates a named alert you trigger manually in the Alerts dialog
  • alert() — fires programmatically when a condition is true, and supports dynamic message strings

For broker automation (connecting to services like 3Commas, Alertatron, or a custom webhook server), you need alert() with a JSON payload in the message.

// ── Alert Messages ───────────────────────────────────────────────────────────

// Named conditions for the Alerts dialog (optional, useful for simple setups)
alertcondition(longCondition,  "Supertrend Long",  "Supertrend flipped bullish")
alertcondition(shortCondition, "Supertrend Short", "Supertrend flipped bearish")

// Webhook-ready JSON alerts (fires automatically when strategy runs)
if longCondition
    alert(
         '{"action": "buy", "symbol": "' + syminfo.ticker + '", ' +
         '"price": ' + str.tostring(close) + ', ' +
         '"atr": '   + str.tostring(ta.atr(atrPeriod), "#.####") + ', ' +
         '"comment": "Supertrend Long"}',
         alert.freq_once_per_bar_close
    )

if shortCondition
    alert(
         '{"action": "sell", "symbol": "' + syminfo.ticker + '", ' +
         '"price": ' + str.tostring(close) + ', ' +
         '"atr": '   + str.tostring(ta.atr(atrPeriod), "#.####") + ', ' +
         '"comment": "Supertrend Short"}',
         alert.freq_once_per_bar_close
    )

The alert.freq_once_per_bar_close flag is critical. It ensures the alert fires only after the bar closes and the signal is confirmed, not mid-candle when the Supertrend might still flip back. This is the single most common source of false entries in automated Supertrend systems.

When you create the alert in TradingView, set the webhook URL to your broker integration endpoint. The JSON payload lands there on every confirmed flip.

Tip: Add a "magic" or "botid" field to the JSON so your webhook server can route signals from multiple strategies without mixing up orders. Something like '"botid": "ST_BTC_1H"' is enough.

Reading the Strategy Tester Output

Once the script is on your chart, open the Strategy Tester tab. Here's what to focus on and what to ignore:

MetricWhat It Tells YouThreshold to Take Seriously
Net Profit %Total return over the test periodPositive after commissions
Profit FactorGross wins / gross losses> 1.5 is solid, > 2.0 is strong
Max Drawdown %Worst peak-to-trough decline< 20% for most retail traders
Win Rate %% of trades that closed positiveTrend strategies: 40–55% is normal
Avg Win / Avg LossReward-to-risk per tradeShould be > 1.5 if win rate is low
Total TradesSample size< 30 trades means nothing statistically

Don't optimize for net profit alone. A strategy with 80% net profit and a 60% drawdown is unlivable. Target a profit factor above 1.5 with drawdown below 20% before considering live deployment.

Also check the trade list for clusters of losses. If 80% of your losing trades happened in a three-month window, that period was probably a ranging market. Ask yourself whether your EMA or HTF filter would have kept you out of it.

This pairs well with the approach covered in the break and retest strategy guide — context matters as much as the signal itself.

Common Mistakes

❌ Mistake: Using alert.freq_once_per_bar instead of alert.freq_once_per_bar_close This fires the alert the moment the condition is true intrabar. Supertrend can flip and flip back within the same candle. You'll get entries on signals that never confirmed.

✅ Always use alert.freq_once_per_bar_close for trend-flip strategies.


❌ Mistake: Backtesting without commissions and slippage A Supertrend strategy on the 15-minute BTC chart might show 200 trades per year. At 0.05% commission per side, that's 10% in fees before you've made a dollar. Backtest with realistic costs from day one.

✅ Set commission_value = 0.05 and slippage = 2 (ticks) as a baseline for crypto. Adjust for your actual broker.


❌ Mistake: Optimizing the factor on a single instrument and calling it done A factor of 2.3 that looks great on BTC/USDT 1H will likely fail on ETH/USDT or any Forex pair. You've curve-fit to one asset's volatility profile.

✅ Test your chosen parameters on at least 3 instruments in the same asset class before considering them robust.


❌ Mistake: Running the strategy without a stop-loss during live testing Even with a trailing stop in the code, things go wrong — connectivity issues, broker errors, gaps at open. Always set a hard stop at the broker level as a safety net.

✅ Use strategy.exit with both a stop and a limit parameter, and configure a backup stop at your broker independently.


❌ Mistake: Ignoring the HTF filter on choppy markets The EMA filter helps, but a sideways 200 EMA means price is crossing it constantly. The HTF Supertrend filter is more decisive in these conditions.

✅ Enable both filters during periods of low ADX (below 20). If the market is genuinely trendless, the best trade is no trade.

Pro Tips

Use ATR normalization to compare settings across instruments. Instead of asking "is a factor of 3.0 right?", ask "does this factor produce an average trade duration of at least 5 bars?" Short average durations signal overtrading regardless of the factor value.

Log the ATR value in your alert payload. Including the ATR in the webhook JSON lets your execution system size positions dynamically based on current volatility — tighter sizing when ATR is high, larger when it's compressed. This is a simple but effective form of volatility-adjusted position sizing.

Separate your indicator script from your strategy script. Keep a clean indicator() version for chart analysis and a separate strategy() version for backtesting and alerts. Mixing them leads to messy code and makes debugging harder.

Test on out-of-sample data. Optimize on the first 70% of your historical data, then validate on the remaining 30% without touching the parameters. If performance degrades sharply on the out-of-sample window, you've overfit.

Build This in Minutes with HorizonAI

If writing Pine Script from scratch isn't your priority, HorizonAI can generate this entire strategy from a plain-English description. The platform is built specifically for traders who want working code without the syntax debugging.

Here are example prompts that would produce scripts like the ones in this article:

  • "Create a Pine Script v6 strategy using Supertrend with ATR period 10 and factor 3.0. Enter long on bullish flip only when price is above the 200 EMA. Add an ATR trailing stop at 1.5x. Fire a webhook alert with a JSON payload on every entry."
  • "Build a Supertrend strategy on Pine Script v6 that filters entries using the daily Supertrend direction. Include strategy.entry, strategy.exit on opposite flip, commission 0.05%, and slippage 2 ticks."
  • "Add alertcondition and alert() calls to my existing Supertrend strategy. The alert message should be a JSON object with action, symbol, price, and ATR fields."

Each prompt generates ready-to-paste code with realistic parameters. You can iterate on it conversationally — "now add a higher-timeframe filter" — without starting over.

Try it free →

FAQs

What's the best Supertrend setting for the 1-hour chart?

There's no universal answer, but 10/2.0 tends to work well for intraday crypto and 10/3.0 for Forex on the 1-hour. Run a parameter sweep across factor values from 1.5 to 4.0 in 0.5 increments and pick the setting that maximizes profit factor (not net profit) with at least 50 trades in the sample.

Why does my Supertrend strategy show different results in live trading vs. the backtest?

The most common causes are: (1) using alert.freq_once_per_bar instead of _close, so alerts fire on unconfirmed signals; (2) request.security() with lookahead_on, which introduces future data in backtests; (3) not accounting for commissions and slippage in the backtest. Fix all three and the gap usually narrows significantly.

Can I use this strategy on stocks or only crypto/Forex?

Yes, but adjust for market hours and gaps. Stocks have overnight gaps that can blow through stop levels. Set your slippage parameter higher (5–10 ticks) to simulate this in backtests, and consider adding a time filter to avoid holding positions into earnings or major macro events.

How do I connect the webhook alert to an actual broker?

You need a middleware service or a custom server that listens for TradingView webhooks. Popular options include 3Commas, Alertatron, WunderTrading, or a self-hosted Python/Node server. The JSON payload in the alert() call gets sent to your webhook URL, and your middleware translates it into a broker API order. The exact setup depends on your broker's API.

Does the ATR trailing stop repaint?

No. The trailing stop is calculated using confirmed bar data and only updates on bar close when strategy.exit is evaluated. It will not repaint historical values once a bar closes.

Final Thoughts

Supertrend is one of the cleaner trend-following tools available precisely because its logic is mechanical and its signals are unambiguous. The challenge has never been the indicator — it's been the gap between seeing a signal and acting on it consistently.

The strategy built here closes that gap: confirmed flips, volatility-adjusted stops, trend filters that cut the noise, and alert payloads that can talk directly to a broker. The Strategy Tester output tells you whether the setup earns its place in your workflow before you risk a dollar.

One concrete thing to do before you close this tab: paste the code into TradingView, run it on your primary instrument with default parameters, and look at the trade list. Not the equity curve — the individual trades. That's where the real information lives.

Related Articles

Questions about automating Supertrend? Join our Discord to discuss with other traders!