TradingView exit-rule comparisons

Supertrend vs Chandelier Exit: state switching and trailing levels

Supertrend switches between carried midpoint bands; Chandelier Exit offsets a rolling extreme by ATR. Matching ATR length and multiplier does not make them equivalent. A Chandelier line that never loosens needs an explicit ratchet. Compare exits from the same entry and distinguish a closing-price decision from a stop already working during the bar.

See the decision guide

What changes when the ATR is held constant

TradingView documents Supertrend as an ATR trend indicator and Chandelier Exit as rolling-high and rolling-low references. This comparison uses their chart-timeframe formulas. It adds one explicitly named Chandelier variant: an entry-decision ratchet, retained through a single long position and cleared after exit. That lifecycle is a strategy choice.

  • Use one ATR series: true range is max(high − low, abs(high − previous close), abs(low − previous close)). After initialization, ATR[t] = ((N − 1) × ATR[t−1] + TR[t]) / N. Both comparisons below use N = 3 and k = 1 to make the arithmetic readable; these are not recommended trading settings.
  • An old high leaving the Chandelier window can lower its reference. A fresh high does not guarantee an increase either: ΔrawLong = ΔhighestHigh − k × ΔATR. Choosing highest close instead of highest high changes the variant.
  • The short-side formulas mirror the long-side arithmetic, but this experiment only trades long. It supplies no evidence about short-sale fills, borrow fees or short-side performance.
MechanismSupertrendChandelier Exit
ReferenceMidpoint M = (high + low) / 2; basic bands M ± k × ATR.Raw long = highest(high, N) − k × ATR; raw short = lowest(low, N) + k × ATR.
MemoryCarry the lower band unless the new basic lower is higher or the previous close was below the previous lower. Reverse the inequalities for the upper band.The raw calculation remembers N bars. The long ratchet additionally retains max(previous ratchet, raw long) after entry.
StateFrom up, close below the updated lower band switches down. From down, close above the updated upper band switches up. Equality holds direction.Two raw exit references have no unique trend state. A long exit test does not automatically open a short.
Volatility expansionThe carried lower band can stay fixed despite a falling basic lower.Raw long can fall. The named ratchet cannot fall during its active lifetime.

Freeze the experiment before comparing results

The Pine strategy below makes one shared entry decision, then changes only its exit branch. All branches wait for the first confirmed bar inside the selected dates with a valid ATR, a complete extreme window, bullish Supertrend and raw Chandelier below the close. This favors an initially bullish state by design; it isolates exit behavior rather than comparing independent entry systems.

  • Use the same standard candlestick chart, exchange feed, session, adjustments, timezone, timeframe and loaded history for all three runs. Keep length, multiplier and dates fixed. Compare the entry timestamp and fill before comparing exits.
  • The entry market order fills on the next available tick, normally the next bar open in this historical close-only setup. One unit, no pyramiding, one tick of adverse slippage per fill and 0.10 account-currency commission per unit per fill are the demonstration assumptions. Check the chart tick size and point value; do not assume every instrument has the fixture economics.
  • All three Pine branches make exit decisions at a confirmed close. Supertrend exits when direction is down. Raw Chandelier exits when close is strictly below the updated raw long. Position ratchet exits when close is strictly below its updated ratchet. Orders execute next tick; these are not fills at the signal close.
  • The ratchet begins at the common entry decision, before the entry fills. It updates on each confirmed bar while the long is open. There is no re-entry. The first confirmed bar whose opening time reaches the end timestamp queues a common end exit if needed; leave a later bar available to fill it. A last-bar pending order is not a completed trade.

Pine Script v6: switch the exit without changing the entry

Paste the complete strategy into Pine Editor. Run each Exit rule on the same chart and save the trade list and Properties. The default dates are an example window; choose dates with enough warm-up and a later execution bar. The script uses chart data and does not load the synthetic fixture below. It has no strategy.exit stop order.

  • The built-in ta.supertrend uses the same length and factor as ta.atr and the Chandelier formula. Its negative direction value means up. The Data Window exposes ATR and direction; orange is the raw long reference and blue is the active ratchet.
  • A raw or ratcheted Chandelier threshold can already be above a gap entry. This strategy still accepts the predetermined common market entry and waits for its closing-bar exit decision. It does not silently reject that trade or promise a protective stop. A different entry validity policy is another experiment.
  • The code intentionally does not trade every Supertrend reversal. Adding re-entry creates a new comparison because different exits can change the availability and timing of future entries.
Original one-entry comparison. Syntax checked on 2026-10-18; syntax acceptance does not verify fills, numerical equivalence to every community script, or profitability.pine
//@version=6
strategy("Supertrend vs Chandelier: one-entry close exits", overlay = true, initial_capital = 100000, default_qty_type = strategy.fixed, default_qty_value = 1, pyramiding = 0, commission_type = strategy.commission.cash_per_contract, commission_value = 0.10, slippage = 1, process_orders_on_close = false, calc_on_every_tick = false, calc_on_order_fills = false)
string method = input.string("Supertrend", "Exit rule", options = ["Supertrend", "Raw Chandelier", "Position ratchet"])
int length = input.int(3, "Shared ATR and extreme length", minval = 1)
float factor = input.float(1.0, "Shared ATR multiplier", minval = 0.1, step = 0.1)
int startTime = input.time(timestamp("01 Jan 2025 00:00 +0000"), "Earliest entry decision")
int endTime = input.time(timestamp("01 Jan 2026 00:00 +0000"), "End decision")
if endTime <= startTime
    runtime.error("End must follow start")
float atr = ta.atr(length)
[st, direction] = ta.supertrend(factor, length)
float raw = ta.highest(high, length) - factor * atr
bool ready = bar_index >= length - 1 and not na(atr) and not na(st)
var bool submitted = false
var float ratchet = na
// This common entry filter is identical for every exit branch.
bool enter = barstate.isconfirmed and ready and not submitted and time >= startTime and time < endTime and direction < 0 and raw < close
if enter
    strategy.entry("L", strategy.long)
    ratchet := raw
    submitted := true
// Ratchet starts on the common entry decision and lasts through this trade.
if barstate.isconfirmed and strategy.position_size > 0
    ratchet := math.max(ratchet, raw)
    bool breached = method == "Supertrend" ? direction > 0 : close < (method == "Raw Chandelier" ? raw : ratchet)
    if breached or time >= endTime
        strategy.close("L", comment = breached ? method : "End window")
if strategy.closedtrades > 0
    ratchet := na
plot(st, "Supertrend state line", color = direction < 0 ? color.green : color.red, linewidth = 2)
plot(raw, "Raw Chandelier long", color = color.orange)
plot(ratchet, "Position ratchet", color = color.blue, style = plot.style_linebr)
plot(atr, "Shared ATR", display = display.data_window)
plot(direction, "ST direction: negative is up", display = display.data_window)

Ten bars that expose the difference

This is a synthetic, seeded calculation in arbitrary price units, independent of a TradingView market chart. At bar 0 close, set previous close = 100, ATR = 2, Supertrend upper = 103, lower = 97 and direction = up. The two preceding highs are 100 and 101. Seed the Chandelier ratchet at 99. Queue the same one-unit market entry at bar 0 close. These explicit states replace chart-history initialization.

  • At bar 3, ATR = (2 × 2.333333… + 3) / 3 = 2.555555…. The lower band becomes 104.5 − ATR = 101.944444…. Raw Chandelier is 106 − ATR = 103.444444…. Same volatility buffer, different anchor.
  • At bar 4, true range is 4 and ATR rises to 3.037037…. Supertrend retains lower 101.944444…. Raw Chandelier falls to 102.962963 while the ratchet holds 103.444444. Bar 5 close 102 breaches both Chandelier versions, but remains above the Supertrend lower band.
  • Bar 6 gaps to 99. Its true range is 4, including the prior close of 102, even though high minus low is only 3. Supertrend turns down at that close, then back up at bar 7. These two consecutive state changes are a local whipsaw example, not an estimated whipsaw frequency.
  • The Supertrend state continues after exit so its flips can be inspected. The Chandelier ratchet is inactive after the bar-6 close-policy exit; the independent replay retains a hypothetical continuous ratchet only to audit its recurrence. The displayed raw level remains meaningful without a position.
Bar: O / H / L / CTR / ATRST upper / lower / stateRaw CE / ratchet
1: 100 / 102 / 100 / 1012 / 2.000000103.000000 / 99.000000 / up100.000000 / 100.000000
2: 101 / 104 / 101 / 1033 / 2.333333103.000000 / 100.166667 / up101.666667 / 101.666667
3: 103 / 106 / 103 / 1053 / 2.555556103.000000 / 101.944444 / up103.444444 / 103.444444
4: 105 / 106 / 102 / 1044 / 3.037037107.037037 / 101.944444 / up102.962963 / 103.444444
5: 104 / 105 / 102 / 1023 / 3.024691106.524691 / 101.944444 / up102.975309 / 103.444444
6: 99 / 101 / 98 / 1004 / 3.349794102.849794 / 101.944444 / down102.650206 / inactive
7: 100 / 105 / 100 / 1045 / 3.899863102.849794 / 98.600137 / up101.100137 / inactive
8: 104 / 105 / 100 / 1015 / 4.266575106.766575 / 98.600137 / up100.733425 / inactive
9: 101 / 106 / 101 / 1055 / 4.511050106.766575 / 98.988950 / up101.488950 / inactive
10: 105 / 106 / 100 / 1016 / 5.007367106.766575 / 98.988950 / up100.992633 / inactive

Identical costs, different order timing

The fixture assumes tick = 0.25, point value = 1 and quantity = 1. Entry fills at bar 1 open plus one tick: 100 + 0.25 = 100.25. Every sell fill loses one tick and every completed round trip pays 0.20 commission. Net P/L = (exit − entry) × 1 − 0.20. These six outcomes are alternative experiments, never six trades in one account.

  • The stop replay is a separate policy, not the Pine close-only strategy report. At each close it replaces the next bar's stop with floor(level / tick) × tick. The initial stop exists with the queued entry. It tests the next open first, then the next low, against that prior level. A gap fill uses the open; a touch fill uses the stop, before adverse slippage.
  • Never test bar 4 low 102 against bar 4 final raw 102.962963 as though that updated order existed throughout bar 4. The executable Chandelier threshold here was calculated at bar 3 close, 103.25 after tick rounding. The difference affects both whether an order triggers and its fill.
  • A resting stop triggers on equality; the closing breach uses strict inequality. A wick can trigger the stop without a closing breach. TradingView documents next-open fills for price orders crossed in gaps; real stop-market execution also depends on available liquidity. A stop-limit can remain unfilled.
  • The earlier Chandelier stop earns more in this invented path, while the later Supertrend close exit loses less than the Chandelier close exit. Changing execution policy changes the ranking. Neither result establishes an edge or supports annualizing ten bars.
Rule / executionDecision or prior orderExit fillNet P/L
Supertrend / closeBar 6 down state; market order next openBar 7: 100 − 0.25 = 99.75−0.70
Raw Chandelier / closeBar 5 close below 102.975309Bar 6: 99 − 0.25 = 98.75−1.70
Position ratchet / closeBar 5 close below 103.444444Bar 6: 99 − 0.25 = 98.75−1.70
Supertrend lower / resting stopPrior lower rounds down to 101.75; bar 6 gaps below itBar 6: 99 − 0.25 = 98.75−1.70
Raw Chandelier / resting stopBar 3 raw rounds down to 103.25; bar 4 low touches itBar 4: 103.25 − 0.25 = 103.00+2.55
Position ratchet / resting stopSame previously placed 103.25 stopBar 4: 103.25 − 0.25 = 103.00+2.55

Independent replay: states, orders and fees

Save this Python 3 program as a file and run it. It reconstructs true range, Wilder ATR, both Supertrend bands, direction, rolling highs and the ratchet from the stated seeds. It then runs a separate order ledger with prior-bar stops, next-open market exits, tick rounding, slippage and commission. Assertions check every reported trade, the ATR gap, the retreating raw line and the two state flips.

  • Zero ATR is valid for a flat input series; this calculation never divides by ATR. The Pine inputs require a positive length and multiplier. The fixture also rejects impossible OHLC ranges.
  • Full precision is retained in calculations. Six-decimal table values are for reading only. Rounding an indicator before comparing a close can change a boundary result; tick rounding belongs to the executable stop specification.
No market download and no Pine execution. The JSON output is an independent arithmetic and timing check of this seeded fixture; it is not a TradingView execution test.python
"""Independent seeded recurrence and one-trade ledger; synthetic prices only."""
import json
import math
from pathlib import Path

BARS = [
    (100, 102, 100, 101), (101, 104, 101, 103),
    (103, 106, 103, 105), (105, 106, 102, 104),
    (104, 105, 102, 102), (99, 101, 98, 100),
    (100, 105, 100, 104), (104, 105, 100, 101),
    (101, 106, 101, 105), (105, 106, 100, 101),
]
# State at bar 0 close. These seeds replace chart-history warm-up.
ATR, UPPER, LOWER, PREV_CLOSE, DIRECTION = 2.0, 103.0, 97.0, 100.0, -1
N, K, TICK, FEE = 3, 1.0, 0.25, 0.10
highs = [100.0, 101.0]
ratchet = 99.0  # bar-0 rolling HH 101 minus ATR 2
states = []
for bar, (o, h, low, c) in enumerate(BARS, 1):
    assert low <= min(o, c) <= max(o, c) <= h
    tr = max(h - low, abs(h - PREV_CLOSE), abs(low - PREV_CLOSE))
    ATR = ((N - 1) * ATR + tr) / N
    basic_u, basic_l = (h + low) / 2 + K * ATR, (h + low) / 2 - K * ATR
    UPPER = basic_u if basic_u < UPPER or PREV_CLOSE > UPPER else UPPER
    LOWER = basic_l if basic_l > LOWER or PREV_CLOSE < LOWER else LOWER
    previous_direction = DIRECTION
    DIRECTION = (-1 if c > UPPER else 1) if DIRECTION == 1 else (1 if c < LOWER else -1)
    highs.append(h)
    raw = max(highs[-N:]) - K * ATR
    ratchet = max(ratchet, raw)
    states.append(dict(bar=bar, o=o, h=h, l=low, c=c, tr=tr, atr=ATR,
                       upper=UPPER, lower=LOWER, direction=DIRECTION,
                       raw=raw, ratchet=ratchet, flip=DIRECTION != previous_direction))
    PREV_CLOSE = c

# Each alternative owns a separate one-unit long, queued at bar 0 close.
entry = BARS[0][0] + TICK
trades = []
for method in ('Supertrend', 'Raw Chandelier', 'Position ratchet'):
    for execution in ('close', 'stop'):
        prior = 97.0 if method == 'Supertrend' else 99.0
        pending_close = False
        for s in states:
            threshold = s['lower'] if method == 'Supertrend' else s['raw'] if method == 'Raw Chandelier' else s['ratchet']
            fill, reason = None, None
            if pending_close:
                fill, reason = s['o'] - TICK, 'next-open market'
            elif execution == 'stop':
                stop = math.floor(prior / TICK) * TICK
                if s['o'] <= stop:
                    fill, reason = s['o'] - TICK, 'gap through prior stop'
                elif s['l'] <= stop:
                    fill, reason = stop - TICK, 'touch of prior stop'
            if fill is not None:
                trades.append(dict(method=method, execution=execution, entry_bar=1,
                                   entry=entry, exit_bar=s['bar'], exit=fill, reason=reason,
                                   gross=fill-entry, fees=2*FEE, net=fill-entry-2*FEE))
                break
            pending_close = execution == 'close' and (s['direction'] > 0 if method == 'Supertrend' else s['c'] < threshold)
            prior = threshold
        else:
            raise AssertionError('Fixture must close all alternatives')

# Boundary checks use executable prior stops, strict close tests, and gap TR.
assert states[3]['raw'] < states[2]['raw']
assert states[3]['ratchet'] == states[2]['ratchet']
assert states[5]['tr'] == 4
assert [s['bar'] for s in states if s['flip']] == [6, 7]
assert not (100 < 100)  # equality does not trigger a close breach
assert 100 <= 100      # equality touches an already-resting stop
expected = {('Supertrend','close'):(7,99.75,-0.70),
            ('Supertrend','stop'):(6,98.75,-1.70),
            ('Raw Chandelier','close'):(6,98.75,-1.70),
            ('Position ratchet','close'):(6,98.75,-1.70),
            ('Raw Chandelier','stop'):(4,103.0,2.55),
            ('Position ratchet','stop'):(4,103.0,2.55)}
for t in trades:
    b, price, net = expected[t['method'], t['execution']]
    assert t['exit_bar'] == b and math.isclose(t['exit'], price) and math.isclose(t['net'], net)
result = dict(assumptions=dict(length=N, multiplier=K, tick=TICK, commission_per_fill=FEE,
                             quantity=1, point_value=1, entry_order='bar 0 close'),
              states=states, trades=trades)
Path(__file__).with_suffix('.json').write_text(json.dumps(result, indent=2) + '\n')
print(json.dumps(result, indent=2))

Choose the rule by the failure you are willing to test

Use Supertrend when the requirement includes a persistent trend state and a closing-price band reversal. Use a raw Chandelier reference when the rolling extreme and changing volatility buffer are the intended inputs. Use the named ratchet when the intended long threshold must not decrease during its defined lifetime. A tighter reference may exit a trend early; a looser reference may retain more adverse movement.

  • After reproducing the mechanics, preselect trending and ranging chart windows. Record exit delay, maximum adverse excursion, bars held and net result with the same costs. Inspect neighboring lengths and multipliers and a later untouched sample. A common initial entry does not remove sample-selection bias.
  • Pine Script AI Coding Agent can draft or edit the comparison from a written rule set and request syntax checking. Provide the entry filter, the ratchet reset, confirmation time, stop placement time, cost model and fixture outputs. Review intermediate values and the actual trade list before relying on any report.
  • The page verifies syntax and a synthetic independent replay. It does not claim a market backtest, live execution, an optimal parameter set or an automatic profitability check.
Where Pineify fits

Pine Script AI Coding Agent

Draft and inspect an exit comparison from explicit ATR, state, entry and execution rules, then request syntax checking.

Draft an exit comparison

Frequently asked questions

Educational comparison, not investment advice. Synthetic prices, seeded states and hypothetical fills are not measured market returns. Backtests and syntax checks do not establish future performance or guarantee stop execution.

Sources and verification

Published by Pineify. Pineify is an independent product and is not affiliated with TradingView. Sources support the technical explanations; examples do not establish trading performance.