Supertrend Reversal Strategy
The Supertrend indicator combines ATR and price to produce trailing support or resistance. When the Supertrend line flips from above to below price or vice versa, it suggests a potential trend change. This strategy trades those flips.
Testing indicates an average annual return of about 151%. It performs best in the stocks market.
On each candle an ATR-based calculation updates the Supertrend level. A switch from above price to below triggers a long entry, while a move from below to above creates a short. The code sample omits explicit stops, so exits are discretionary or managed by a separate risk module.
The indicator can react quickly to volatility, so traders often combine it with additional filters to reduce whipsaws.
Details
- Entry Criteria: Supertrend switches sides relative to price.
- Long/Short: Both.
- Exit Criteria: Manual or external stop.
- Stops: Not defined.
- Default Values:
Period= 10Multiplier= 3.0CandleType= 15 minute
- Filters:
- Category: Trend following
- Direction: Both
- Indicators: Supertrend
- Stops: Optional
- Complexity: Basic
- Timeframe: Intraday
- Seasonality: No
- Neural networks: No
- Divergence: No
- Risk level: Medium
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Supertrend Reversal strategy.
/// Uses the built-in SuperTrend indicator.
/// Enters long when SuperTrend flips to uptrend (below price).
/// Enters short when SuperTrend flips to downtrend (above price).
/// Uses cooldown to control trade frequency.
/// </summary>
public class SupertrendReversalStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _cooldownBars;
private bool? _prevIsUpTrend;
private int _cooldown;
/// <summary>
/// ATR period for SuperTrend.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// ATR multiplier for SuperTrend.
/// </summary>
public decimal Multiplier
{
get => _multiplier.Value;
set => _multiplier.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Cooldown bars.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public SupertrendReversalStrategy()
{
_period = Param(nameof(Period), 10)
.SetRange(7, 20)
.SetDisplay("Period", "ATR period for SuperTrend", "SuperTrend");
_multiplier = Param(nameof(Multiplier), 3.0m)
.SetRange(2.0m, 4.0m)
.SetDisplay("Multiplier", "ATR multiplier for SuperTrend", "SuperTrend");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_cooldownBars = Param(nameof(CooldownBars), 500)
.SetRange(1, 1000)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevIsUpTrend = null;
_cooldown = default;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevIsUpTrend = null;
_cooldown = 0;
var superTrend = new SuperTrend
{
Length = Period,
Multiplier = Multiplier
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(superTrend, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, superTrend);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue stValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!stValue.IsFormed)
return;
var stTyped = (SuperTrendIndicatorValue)stValue;
var isUpTrend = stTyped.IsUpTrend;
if (_prevIsUpTrend == null)
{
_prevIsUpTrend = isUpTrend;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevIsUpTrend = isUpTrend;
return;
}
// SuperTrend flipped to uptrend = bullish
var flippedUp = _prevIsUpTrend == false && isUpTrend;
// SuperTrend flipped to downtrend = bearish
var flippedDown = _prevIsUpTrend == true && !isUpTrend;
if (Position == 0 && flippedUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (Position == 0 && flippedDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position > 0 && flippedDown)
{
SellMarket();
_cooldown = CooldownBars;
}
else if (Position < 0 && flippedUp)
{
BuyMarket();
_cooldown = CooldownBars;
}
_prevIsUpTrend = isUpTrend;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import SuperTrend
from StockSharp.Algo.Strategies import Strategy
class supertrend_reversal_strategy(Strategy):
"""
Supertrend Reversal strategy.
Enters long when SuperTrend flips to uptrend (below price).
Enters short when SuperTrend flips to downtrend (above price).
Uses cooldown to control trade frequency.
"""
def __init__(self):
super(supertrend_reversal_strategy, self).__init__()
self._period = self.Param("Period", 10).SetDisplay("Period", "ATR period for SuperTrend", "SuperTrend")
self._multiplier = self.Param("Multiplier", 3.0).SetDisplay("Multiplier", "ATR multiplier for SuperTrend", "SuperTrend")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._cooldown_bars = self.Param("CooldownBars", 500).SetDisplay("Cooldown Bars", "Bars to wait between trades", "General")
self._prev_is_up_trend = None
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(supertrend_reversal_strategy, self).OnReseted()
self._prev_is_up_trend = None
self._cooldown = 0
def OnStarted2(self, time):
super(supertrend_reversal_strategy, self).OnStarted2(time)
self._prev_is_up_trend = None
self._cooldown = 0
st = SuperTrend()
st.Length = self._period.Value
st.Multiplier = self._multiplier.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(st, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, st)
self.DrawOwnTrades(area)
def _process_candle(self, candle, st_iv):
if candle.State != CandleStates.Finished:
return
if not st_iv.IsFormed:
return
is_up_trend = st_iv.IsUpTrend
if self._prev_is_up_trend is None:
self._prev_is_up_trend = is_up_trend
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_is_up_trend = is_up_trend
return
cd = self._cooldown_bars.Value
# SuperTrend flipped to uptrend = bullish
flipped_up = self._prev_is_up_trend == False and is_up_trend
# SuperTrend flipped to downtrend = bearish
flipped_down = self._prev_is_up_trend == True and not is_up_trend
if self.Position == 0 and flipped_up:
self.BuyMarket()
self._cooldown = cd
elif self.Position == 0 and flipped_down:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0 and flipped_down:
self.SellMarket()
self._cooldown = cd
elif self.Position < 0 and flipped_up:
self.BuyMarket()
self._cooldown = cd
self._prev_is_up_trend = is_up_trend
def CreateClone(self):
return supertrend_reversal_strategy()