Super Trend
Strategy based on Supertrend indicator
Testing indicates an average annual return of about 67%. It performs best in the stocks market.
Super Trend calculates a dynamic line from ATR that flips between support and resistance. Price crossing above it turns the bias bullish, and crossing below turns it bearish. The trade ends when the line reverses.
By following this adaptive line, the strategy attempts to capture sustained runs while minimizing whipsaws. Because the stop level trails price, it locks in profits once momentum fades.
Details
- Entry Criteria: Signals based on ATR, Supertrend.
- Long/Short: Both directions.
- Exit Criteria: Opposite signal.
- Stops: No.
- Default Values:
Period= 10Multiplier= 3.0mCandleType= TimeSpan.FromMinutes(5)
- Filters:
- Category: Trend
- Direction: Both
- Indicators: ATR, Supertrend
- Stops: No
- Complexity: Basic
- Timeframe: Intraday (5m)
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy based on Supertrend indicator.
/// It enters long position when price is above Supertrend line and short position when price is below Supertrend line.
/// </summary>
public class SupertrendStrategy : Strategy
{
private readonly StrategyParam<int> _period;
private readonly StrategyParam<decimal> _multiplier;
private readonly StrategyParam<DataType> _candleType;
// Current state tracking
private bool _prevIsPriceAboveSupertrend;
private decimal _prevSupertrendValue;
/// <summary>
/// Period for Supertrend calculation.
/// </summary>
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
/// <summary>
/// Multiplier for Supertrend calculation.
/// </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>
/// Initialize the Supertrend strategy.
/// </summary>
public SupertrendStrategy()
{
_period = Param(nameof(Period), 300)
.SetDisplay("Period", "Period for Supertrend calculation", "Indicators")
.SetOptimize(7, 21, 2);
_multiplier = Param(nameof(Multiplier), 50.0m)
.SetDisplay("Multiplier", "Multiplier for Supertrend calculation", "Indicators")
.SetOptimize(2.0m, 4.0m, 0.5m);
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(1).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevIsPriceAboveSupertrend = false;
_prevSupertrendValue = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create custom supertrend indicator
// Since StockSharp doesn't have a built-in Supertrend indicator,
// we'll use ATR to calculate the basic components
var atr = new AverageTrueRange { Length = Period };
// Create subscription
var subscription = SubscribeCandles(CandleType);
// We'll process candles manually and calculate Supertrend in the handler
subscription
.Bind(atr, ProcessCandle)
.Start();
// Setup chart visualization if available
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue)
{
// Skip unfinished candles
if (candle.State != CandleStates.Finished)
return;
// Check if strategy is ready to trade
if (!IsFormedAndOnlineAndAllowTrading())
return;
// Calculate Supertrend components
var medianPrice = (candle.HighPrice + candle.LowPrice) / 2;
var basicUpperBand = medianPrice + Multiplier * atrValue;
var basicLowerBand = medianPrice - Multiplier * atrValue;
// We need to track previous values to implement the Supertrend logic
decimal supertrendValue;
// If this is the first processed candle, initialize values
if (_prevSupertrendValue == 0)
{
supertrendValue = candle.ClosePrice > medianPrice ? basicLowerBand : basicUpperBand;
_prevSupertrendValue = supertrendValue;
_prevIsPriceAboveSupertrend = candle.ClosePrice > supertrendValue;
return;
}
// Determine current Supertrend value based on previous value and current price
if (_prevSupertrendValue <= candle.HighPrice)
{
// Previous Supertrend was resistance
supertrendValue = Math.Max(basicLowerBand, _prevSupertrendValue);
}
else if (_prevSupertrendValue >= candle.LowPrice)
{
// Previous Supertrend was support
supertrendValue = Math.Min(basicUpperBand, _prevSupertrendValue);
}
else
{
// Price crossed the Supertrend
supertrendValue = candle.ClosePrice > _prevSupertrendValue ? basicLowerBand : basicUpperBand;
}
// Check if price is above or below Supertrend
var isPriceAboveSupertrend = candle.ClosePrice > supertrendValue;
// Detect crossovers
var isCrossedAbove = isPriceAboveSupertrend && !_prevIsPriceAboveSupertrend;
var isCrossedBelow = !isPriceAboveSupertrend && _prevIsPriceAboveSupertrend;
// Trading logic
if (isCrossedAbove && Position <= 0)
{
// Price crossed above Supertrend - Buy signal
var volume = Volume + Math.Abs(Position);
BuyMarket(volume);
LogInfo($"Buy signal: Price ({candle.ClosePrice}) crossed above Supertrend ({supertrendValue})");
}
else if (isCrossedBelow && Position >= 0)
{
// Price crossed below Supertrend - Sell signal
var volume = Volume + Math.Abs(Position);
SellMarket(volume);
LogInfo($"Sell signal: Price ({candle.ClosePrice}) crossed below Supertrend ({supertrendValue})");
}
// Update state for the next candle
_prevSupertrendValue = supertrendValue;
_prevIsPriceAboveSupertrend = isPriceAboveSupertrend;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import AverageTrueRange
from StockSharp.Algo.Strategies import Strategy
class supertrend_strategy(Strategy):
"""
Strategy based on Supertrend indicator.
Enters long when price crosses above Supertrend, short when price crosses below.
"""
def __init__(self):
super(supertrend_strategy, self).__init__()
self._period = self.Param("Period", 300).SetDisplay("Period", "Period for Supertrend calculation", "Indicators")
self._multiplier = self.Param("Multiplier", 50.0).SetDisplay("Multiplier", "Multiplier for Supertrend calculation", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(1))).SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_is_price_above = False
self._prev_supertrend = 0.0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(supertrend_strategy, self).OnReseted()
self._prev_is_price_above = False
self._prev_supertrend = 0.0
def OnStarted2(self, time):
super(supertrend_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = self._period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(atr, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _process_candle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
atr_v = float(atr_val)
mult = float(self._multiplier.Value)
median = float(candle.HighPrice + candle.LowPrice) / 2.0
basic_upper = median + mult * atr_v
basic_lower = median - mult * atr_v
if self._prev_supertrend == 0:
st = basic_lower if float(candle.ClosePrice) > median else basic_upper
self._prev_supertrend = st
self._prev_is_price_above = float(candle.ClosePrice) > st
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
if self._prev_supertrend <= high:
st = max(basic_lower, self._prev_supertrend)
elif self._prev_supertrend >= low:
st = min(basic_upper, self._prev_supertrend)
else:
st = basic_lower if close > self._prev_supertrend else basic_upper
is_above = close > st
crossed_above = is_above and not self._prev_is_price_above
crossed_below = not is_above and self._prev_is_price_above
if crossed_above and self.Position <= 0:
self.BuyMarket(self.Volume + abs(self.Position))
elif crossed_below and self.Position >= 0:
self.SellMarket(self.Volume + abs(self.Position))
self._prev_supertrend = st
self._prev_is_price_above = is_above
def CreateClone(self):
return supertrend_strategy()