Supertrend Momentum Filter
The Supertrend Momentum Filter strategy is built around Supertrend and Momentum indicators.
Signals trigger when its indicators confirms filtered entries on intraday (5m) data. This makes the method suitable for active traders.
Stops rely on ATR multiples and factors like SupertrendPeriod, SupertrendMultiplier. Adjust these defaults to balance risk and reward.
Details
- Entry Criteria: see implementation for indicator conditions.
- Long/Short: Both directions.
- Exit Criteria: opposite signal or stop logic.
- Stops: Yes, using indicator-based calculations.
- Default Values:
SupertrendPeriod = 10SupertrendMultiplier = 3.0mMomentumPeriod = 14CandleType = TimeSpan.FromMinutes(5).TimeFrame()
- Filters:
- Category: Trend following
- Direction: Both
- Indicators: multiple indicators
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Intraday (5m)
- Seasonality: No
- Neural Networks: No
- Divergence: No
- Risk Level: Medium
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trend-following strategy that trades SuperTrend direction only when momentum confirms acceleration.
/// </summary>
public class SupertrendWithMomentumStrategy : Strategy
{
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<int> _momentumPeriod;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<decimal> _stopLossPercent;
private readonly StrategyParam<DataType> _candleType;
private SuperTrend _supertrend;
private Momentum _momentum;
private decimal _prevMomentum;
private bool _isInitialized;
private int _cooldown;
/// <summary>
/// SuperTrend period.
/// </summary>
public int SupertrendPeriod
{
get => _supertrendPeriod.Value;
set => _supertrendPeriod.Value = value;
}
/// <summary>
/// SuperTrend multiplier.
/// </summary>
public decimal SupertrendMultiplier
{
get => _supertrendMultiplier.Value;
set => _supertrendMultiplier.Value = value;
}
/// <summary>
/// Momentum period.
/// </summary>
public int MomentumPeriod
{
get => _momentumPeriod.Value;
set => _momentumPeriod.Value = value;
}
/// <summary>
/// Bars to wait between orders.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Stop loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public SupertrendWithMomentumStrategy()
{
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetRange(2, 50)
.SetDisplay("Supertrend Period", "Period of the SuperTrend indicator", "Indicators");
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3m)
.SetRange(0.5m, 10m)
.SetDisplay("Supertrend Multiplier", "Multiplier of the SuperTrend indicator", "Indicators");
_momentumPeriod = Param(nameof(MomentumPeriod), 14)
.SetRange(2, 100)
.SetDisplay("Momentum Period", "Period of the Momentum indicator", "Indicators");
_cooldownBars = Param(nameof(CooldownBars), 84)
.SetRange(1, 500)
.SetDisplay("Cooldown Bars", "Bars to wait between orders", "Risk");
_stopLossPercent = Param(nameof(StopLossPercent), 2m)
.SetRange(0.5m, 10m)
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
if (Security != null)
yield return (Security, CandleType);
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_supertrend = null;
_momentum = null;
_prevMomentum = 0m;
_isInitialized = false;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
if (Security == null)
throw new InvalidOperationException("Security is not specified.");
_supertrend = new SuperTrend
{
Length = SupertrendPeriod,
Multiplier = SupertrendMultiplier,
};
_momentum = new Momentum { Length = MomentumPeriod };
_cooldown = 0;
_isInitialized = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_supertrend, _momentum, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _supertrend);
DrawIndicator(area, _momentum);
DrawOwnTrades(area);
}
StartProtection(new Unit(0, UnitTypes.Absolute), new Unit(StopLossPercent, UnitTypes.Percent), false);
}
private void ProcessCandle(ICandleMessage candle, decimal supertrendValue, decimal momentumValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_supertrend.IsFormed || !_momentum.IsFormed)
return;
if (ProcessState != ProcessStates.Started)
return;
if (!_isInitialized)
{
_prevMomentum = momentumValue;
_isInitialized = true;
return;
}
if (_cooldown > 0)
{
_cooldown--;
_prevMomentum = momentumValue;
return;
}
var price = candle.ClosePrice;
var isAboveSupertrend = price > supertrendValue;
var isBelowSupertrend = price < supertrendValue;
var isMomentumRising = momentumValue > _prevMomentum;
var isMomentumFalling = momentumValue < _prevMomentum;
if (Position == 0)
{
if (isAboveSupertrend && isMomentumRising && momentumValue >= 100m)
{
BuyMarket();
_cooldown = CooldownBars;
}
else if (isBelowSupertrend && isMomentumFalling && momentumValue <= 100m)
{
SellMarket();
_cooldown = CooldownBars;
}
}
else if (Position > 0)
{
if (isBelowSupertrend || isMomentumFalling)
{
SellMarket(Math.Abs(Position));
_cooldown = CooldownBars;
}
}
else if (Position < 0)
{
if (isAboveSupertrend || isMomentumRising)
{
BuyMarket(Math.Abs(Position));
_cooldown = CooldownBars;
}
}
_prevMomentum = momentumValue;
}
}
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, Decimal
from StockSharp.Messages import DataType, CandleStates, Unit, UnitTypes
from StockSharp.Algo.Indicators import SuperTrend, Momentum
from StockSharp.Algo.Strategies import Strategy
class supertrend_momentum_filter_strategy(Strategy):
"""
Trend-following strategy that trades SuperTrend direction only when momentum confirms acceleration.
"""
def __init__(self):
super(supertrend_momentum_filter_strategy, self).__init__()
self._supertrend_period = self.Param("SupertrendPeriod", 10) \
.SetRange(2, 50) \
.SetDisplay("Supertrend Period", "Period of the SuperTrend indicator", "Indicators")
self._supertrend_multiplier = self.Param("SupertrendMultiplier", 3.0) \
.SetRange(0.5, 10.0) \
.SetDisplay("Supertrend Multiplier", "Multiplier of the SuperTrend indicator", "Indicators")
self._momentum_period = self.Param("MomentumPeriod", 14) \
.SetRange(2, 100) \
.SetDisplay("Momentum Period", "Period of the Momentum indicator", "Indicators")
self._cooldown_bars = self.Param("CooldownBars", 84) \
.SetRange(1, 500) \
.SetDisplay("Cooldown Bars", "Bars to wait between orders", "Risk")
self._stop_loss_percent = self.Param("StopLossPercent", 2.0) \
.SetRange(0.5, 10.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._prev_momentum = 0.0
self._is_initialized = False
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(supertrend_momentum_filter_strategy, self).OnReseted()
self._prev_momentum = 0.0
self._is_initialized = False
self._cooldown = 0
def OnStarted2(self, time):
super(supertrend_momentum_filter_strategy, self).OnStarted2(time)
supertrend = SuperTrend()
supertrend.Length = int(self._supertrend_period.Value)
supertrend.Multiplier = Decimal(self._supertrend_multiplier.Value)
momentum = Momentum()
momentum.Length = int(self._momentum_period.Value)
self._cooldown = 0
self._is_initialized = False
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(supertrend, momentum, self._process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, supertrend)
self.DrawIndicator(area, momentum)
self.DrawOwnTrades(area)
self.StartProtection(
Unit(0, UnitTypes.Absolute),
Unit(self._stop_loss_percent.Value, UnitTypes.Percent),
False
)
def _process_candle(self, candle, supertrend_value, momentum_value):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
if not self._is_initialized:
self._prev_momentum = float(momentum_value)
self._is_initialized = True
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_momentum = float(momentum_value)
return
price = float(candle.ClosePrice)
st_val = float(supertrend_value)
mom_val = float(momentum_value)
is_above_supertrend = price > st_val
is_below_supertrend = price < st_val
is_momentum_rising = mom_val > self._prev_momentum
is_momentum_falling = mom_val < self._prev_momentum
cd = int(self._cooldown_bars.Value)
if self.Position == 0:
if is_above_supertrend and is_momentum_rising and mom_val >= 100.0:
self.BuyMarket()
self._cooldown = cd
elif is_below_supertrend and is_momentum_falling and mom_val <= 100.0:
self.SellMarket()
self._cooldown = cd
elif self.Position > 0:
if is_below_supertrend or is_momentum_falling:
self.SellMarket(Math.Abs(self.Position))
self._cooldown = cd
elif self.Position < 0:
if is_above_supertrend or is_momentum_rising:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown = cd
self._prev_momentum = mom_val
def CreateClone(self):
return supertrend_momentum_filter_strategy()