Module G · Strategy Playbook - Chapter 29

Strategy: Supertrend System

Build the popular ATR-based Supertrend from scratch with a for-loop, plot the trailing stop, and trade it.

StrategyBacktest
What you'll learn
  • ·The Supertrend idea
  • ·ATR bands & the loop
  • ·Trend state & flips
  • ·Trailing-stop plot
  • ·Signals & backtest
  • ·Factor & period tuning

The crossover system in the last chapter turns on two lines crossing. The Supertrend turns on something more intuitive: a single line that hugs the price, sits below it in an uptrend and flips above it in a downtrend, trailing along like a stop you never have to move by hand. Traders love it because the chart reads itself - green line below, stay long; red line above, stay short or stand aside.

Good to know

Supertrend is built on the ATR (Average True Range), devised by J. Welles Wilder in his 1978 book - the same volume that introduced the RSI, ADX and Parabolic SAR.

That clean picture hides a small amount of genuine bar-by-bar logic, which is why the Supertrend is the perfect place to use the one tool we have mostly avoided: the for-loop. The line at each bar depends on what the line did on the bar before, and that kind of carry-the-state-forward calculation is exactly what a loop is for. We will build it from scratch, plot it, trade it, and tune it.

How the Supertrend is built

Start with a band above and below the bar's midpoint, scaled by recent volatility:

  • mid = (H + L) / 2
  • Up = mid + Factor * ATR(Pd) - the upper band
  • Dn = mid - Factor * ATR(Pd) - the lower band

ATR(Pd) is the average true range over Pd bars - a measure of how much the instrument typically moves - and Factor decides how far out the bands sit. Now the rule: if the close pushes above the previous upper band, the trend is up; if it closes below the previous lower band, the trend is down; otherwise the trend simply continues. Once a trend is established, we drag the relevant band in the trade's favour so it behaves like a trailing stop and never loosens. Because each bar looks back at the previous bar's band and trend, we need a loop.

Building it with a for-loop

Here is the core engine. It fills three arrays as it walks forward: trend (+1 up, -1 down), and the two halves of the visible line, TrendUp and TrendDown.

_SECTION_BEGIN("Supertrend System");

// === Inputs (swap Param for Optimize from Chapter 26 to tune) ===
Factor = Param("Factor (ATR multiplier)", 3, 1, 10, 0.1);
Pd     = Param("ATR Period", 10, 1, 50, 1);

// === Raw bands around the bar midpoint ===
mid  = (H + L) / 2;
Up   = mid + Factor * ATR(Pd);   // upper band
Dn   = mid - Factor * ATR(Pd);   // lower band
iATR = ATR(Pd);

// === Arrays we fill bar by bar ===
trend     = Null;   // +1 in an uptrend, -1 in a downtrend
TrendUp   = Null;   // green line, drawn only in uptrends
TrendDown = Null;   // red line, drawn only in downtrends
trend[0]  = 1;      // assume the first bar is an uptrend
changeOfTrend = 0;

for (i = 1; i < BarCount; i++)
{
    // 1. Decide this bar's trend
    if (Close[i] > Up[i-1])       trend[i] = 1;            // broke above upper band
    else if (Close[i] < Dn[i-1])  trend[i] = -1;           // broke below lower band
    else                          trend[i] = trend[i-1];   // no breakout - carry on
    if (trend[i] != trend[i-1])   changeOfTrend = 1;       // the trend just flipped

    // 2. Note the direction of any flip this bar
    flag  = trend[i] < 0 AND trend[i-1] > 0;   // up   -> down
    flagh = trend[i] > 0 AND trend[i-1] < 0;   // down -> up

    // 3. Trail the bands so the stop only tightens
    if (trend[i] > 0 AND Dn[i] < Dn[i-1]) Dn[i] = Dn[i-1]; // up: ratchet the stop up
    if (trend[i] < 0 AND Up[i] > Up[i-1]) Up[i] = Up[i-1]; // down: ratchet the stop down

    // 4. On a fresh flip, reset the new stop to the raw band
    if (flag)  Up[i] = (H[i] + L[i]) / 2 + Factor * iATR[i];
    if (flagh) Dn[i] = (H[i] + L[i]) / 2 - Factor * iATR[i];

    // 5. The visible line is whichever band is active
    if (trend[i] == 1)
    {
        TrendUp[i] = Dn[i];
        if (changeOfTrend == 1) { TrendUp[i-1] = TrendDown[i-1]; changeOfTrend = 0; }
    }
    else
    {
        TrendDown[i] = Up[i];
        if (changeOfTrend == 1) { TrendDown[i-1] = TrendUp[i-1]; changeOfTrend = 0; }
    }
}
Key idea

The loop starts at i = 1, never i = 0, because every line inside reaches back to i-1. Bar zero has nothing before it, so we seed it by hand with trend[0] = 1. Reaching back past the start of an array is one of the classic loop bugs - always seed the first bar and start the loop at one.

That little handover in step 5 (TrendUp[i-1] = TrendDown[i-1]) just stitches the green and red segments together at the moment of a flip, so the line looks continuous instead of leaving a gap.

Plotting and signalling

With the engine done, the rest is the familiar system scaffolding - plot the price, plot the line, and turn the trend array into clean, non-repainting signals.

// === Chart ===
SetChartOptions(0, chartShowArrows | chartShowDates);
_N(Title = StrFormat("{{NAME}} - {{INTERVAL}} {{DATE}}  O %g  H %g  L %g  C %g  (%.1f%%)",
    O, H, L, C, SelectedValue(ROC(C, 1))));
Plot(Close,     "Close",          colorDefault, styleCandle | styleNoTitle);
Plot(TrendUp,   "Supertrend Up",  colorGreen,   styleThick);
Plot(TrendDown, "Supertrend Dn",  colorRed,     styleThick);

// === Signals from the trend state ===
Buy  = trend == 1;
Sell = trend == -1;
Buy  = ExRem(Buy,  Sell);
Sell = ExRem(Sell, Buy);

Short = Sell;
Cover = Buy;

// === Non-repainting one-bar delay ===
SetTradeDelays(0, 0, 0, 0);
Buy   = Ref(Buy,   -1);
Sell  = Ref(Sell,  -1);
Short = Ref(Short, -1);
Cover = Ref(Cover, -1);

BuyPrice = SellPrice = ShortPrice = CoverPrice = Open;
SetPositionSize(100, spsPercentOfEquity);

// === Arrows ===
PlotShapes(IIf(Buy,   shapeUpArrow,   shapeNone), colorLime,   0, Low,  -25);
PlotShapes(IIf(Short, shapeDownArrow, shapeNone), colorOrange, 0, High,  25);

_SECTION_END();

This is a deliberately focused build. The author's original Supertrend ships with a GFX dashboard and a top status bar; we have dropped all of that to keep the eye on the engine. Once you understand the loop, bolting a dashboard back on is just decoration.

Reading it on the chart

Apply the formula and you will see the price candles with a single line that flips sides. While the green line sits below price, the trend is up and you are long; the instant a close breaks the trailing band, the line jumps to the other side, an arrow prints, and the position reverses. Because the band only ever tightens, the line acts as a built-in trailing stop that locks in more of a trend as it runs.

Tip

The Supertrend is a pure reversal system as written - it is always in the market, flipping from long to short and back. That is fine for trending instruments but punishing in a range. If you only want longs, simply delete the Short/Cover lines and let Sell flatten you to cash; the line still trails your stop.

Tuning Factor and ATR period

Two dials shape everything: Factor (how wide the bands sit) and Pd (how many bars the ATR averages). A larger Factor or longer Pd gives a slower, calmer line that ignores small wiggles but reacts late; a smaller one is twitchy and flips often. Tune them the disciplined way from Chapter 26:

Factor = Optimize("Factor",     3,  1,  6, 0.5);
Pd     = Optimize("ATR Period", 10, 5, 30, 1);

Sweep both, read the 2D heatmap, and choose a pair from a broad green plateau - not the single tallest cell. A Factor of 3 with a 10-bar ATR is a sensible default for daily Indian equities and indices, but let the data on your instrument and timeframe confirm it.

Then backtest the chosen settings in the Analysis window and read the report the usual way - CAR and drawdown first, then CAR/MDD. Like the EMA crossover, this is a trend system: expect a modest win rate carried by a handful of large, trend-riding winners.

Heads up

A loop-based system is slower to compute than a vectorised one, and a flip-on-every-bar reversal system racks up trades - so costs bite hard. Always include realistic brokerage and slippage in the backtest, and prove the settings in sandbox trading (analyzer mode in OpenAlgo) before risking capital. This is education, not advice.

Try it yourself

  • Run the Supertrend on CRUDEOIL with the defaults, then double Factor to 6 and watch the trade count collapse.
  • Strip it to long-only by removing the Short/Cover lines and compare the drawdown.
  • Optimise Factor and Pd together and pick a robust pair from the heatmap.
  • Add a higher-timeframe trend filter later (Chapter 32) so you only take Supertrend longs when the weekly trend agrees.

Recap

  • The Supertrend is an ATR band that trails price and flips sides; building it needs a for-loop because each bar depends on the one before.
  • Seed bar zero (trend[0] = 1) and start the loop at i = 1 to avoid reaching past the array's start.
  • The trailing logic only ever tightens the active band, so the line doubles as a stop.
  • Turn the trend array into signals, then make them non-repainting with Ref(..., -1) and SetTradeDelays(0,0,0,0).
  • Tune Factor and the ATR period with Optimize, mind the trade count and costs, and validate in sandbox.

Next we move to the intraday world, where the benchmark every day-trader watches is a line that resets each morning: VWAP.