Supertrend Stochastic Strategy
Supertrend + Stochastic strategy. Strategy enters trades when Supertrend indicates trend direction and Stochastic confirms with oversold/overbought conditions.
Testing indicates an average annual return of about 142%. It performs best in the stocks market.
Supertrend marks the trend, and Stochastic points out temporary counter moves. Entries happen once Stochastic exits oversold or overbought against the trend.
Best for momentum traders needing clear trend cues. ATR values define the stop distance.
Details
- Entry Criteria:
- Long:
Close > Supertrend && StochK < 20 - Short:
Close < Supertrend && StochK > 80
- Long:
- Long/Short: Both
- Exit Criteria: Supertrend reversal
- Stops: Uses Supertrend as trailing stop
- Default Values:
SupertrendPeriod= 10SupertrendMultiplier= 3.0mStochPeriod= 14StochK= 3StochD= 3CandleType= TimeSpan.FromMinutes(5).TimeFrame()
- Filters:
- Category: Mean reversion
- Direction: Both
- Indicators: Supertrend, Stochastic Oscillator
- Stops: Yes
- Complexity: Intermediate
- Timeframe: Mid-term
- 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>
/// Supertrend + Stochastic strategy.
/// Strategy enters trades when Supertrend indicates trend direction and Stochastic confirms with oversold/overbought conditions.
/// </summary>
public class SupertrendStochasticStrategy : Strategy
{
private readonly StrategyParam<int> _supertrendPeriod;
private readonly StrategyParam<decimal> _supertrendMultiplier;
private readonly StrategyParam<int> _stochPeriod;
private readonly StrategyParam<int> _stochK;
private readonly StrategyParam<int> _stochD;
private readonly StrategyParam<int> _cooldownBars;
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLossPercent;
private int _cooldown;
// Indicators
private SuperTrend _supertrend;
private StochasticOscillator _stochastic;
/// <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>
/// Stochastic period.
/// </summary>
public int StochPeriod
{
get => _stochPeriod.Value;
set => _stochPeriod.Value = value;
}
/// <summary>
/// Stochastic %K period.
/// </summary>
public int StochK
{
get => _stochK.Value;
set => _stochK.Value = value;
}
/// <summary>
/// Stochastic %D period.
/// </summary>
public int StochD
{
get => _stochD.Value;
set => _stochD.Value = value;
}
/// <summary>
/// Bars to wait between trades.
/// </summary>
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Stop-loss percentage.
/// </summary>
public decimal StopLossPercent
{
get => _stopLossPercent.Value;
set => _stopLossPercent.Value = value;
}
/// <summary>
/// Constructor.
/// </summary>
public SupertrendStochasticStrategy()
{
_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Supertrend Period", "Supertrend ATR period length", "Supertrend")
.SetOptimize(5, 20, 1);
_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3.0m)
.SetGreaterThanZero()
.SetDisplay("Supertrend Multiplier", "Supertrend ATR multiplier", "Supertrend")
.SetOptimize(1.0m, 5.0m, 0.5m);
_stochPeriod = Param(nameof(StochPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("Stochastic Period", "Stochastic oscillator period", "Stochastic")
.SetOptimize(5, 30, 5);
_stochK = Param(nameof(StochK), 3)
.SetGreaterThanZero()
.SetDisplay("Stochastic %K", "Stochastic %K period", "Stochastic")
.SetOptimize(1, 10, 1);
_stochD = Param(nameof(StochD), 3)
.SetGreaterThanZero()
.SetDisplay("Stochastic %D", "Stochastic %D period", "Stochastic")
.SetOptimize(1, 10, 1);
_cooldownBars = Param(nameof(CooldownBars), 8)
.SetRange(1, 50)
.SetDisplay("Cooldown Bars", "Bars between trades", "General");
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_stopLossPercent = Param(nameof(StopLossPercent), 1.0m)
.SetNotNegative()
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk Management")
.SetOptimize(0.5m, 2.0m, 0.5m);
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_supertrend = null;
_stochastic = null;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Create indicators
_supertrend = new()
{
Length = SupertrendPeriod,
Multiplier = SupertrendMultiplier
};
_stochastic = new()
{
K = { Length = StochK },
D = { Length = StochD },
};
Indicators.Add(_supertrend);
Indicators.Add(_stochastic);
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
StartProtection(
takeProfit: new Unit(2, UnitTypes.Percent),
stopLoss: new Unit(StopLossPercent, UnitTypes.Percent));
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _supertrend);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var stResult = _supertrend.Process(candle);
var stochResult = _stochastic.Process(candle);
if (!_supertrend.IsFormed || !_stochastic.IsFormed)
return;
if (stResult is not SuperTrendIndicatorValue stVal)
return;
if (stochResult is not StochasticOscillatorValue stochTyped || stochTyped.K is not decimal stochK)
return;
var isBullish = stVal.IsUpTrend;
if (_cooldown > 0)
{
_cooldown--;
return;
}
if (Position != 0)
return;
// Buy: bullish supertrend + stochastic oversold area
if (isBullish && stochK < 30)
{
BuyMarket();
_cooldown = CooldownBars;
}
// Sell: bearish supertrend + stochastic overbought area
else if (!isBullish && stochK > 70)
{
SellMarket();
_cooldown = CooldownBars;
}
}
}
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, Unit, UnitTypes
from StockSharp.Algo.Indicators import SuperTrend, StochasticOscillator
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class supertrend_stochastic_strategy(Strategy):
"""
Supertrend + Stochastic strategy.
Enters trades when Supertrend indicates trend direction and Stochastic confirms.
Uses StartProtection for exits.
"""
def __init__(self):
super(supertrend_stochastic_strategy, self).__init__()
self._supertrendPeriod = self.Param("SupertrendPeriod", 10) \
.SetDisplay("Supertrend Period", "Supertrend ATR period length", "Supertrend")
self._supertrendMultiplier = self.Param("SupertrendMultiplier", 3.0) \
.SetDisplay("Supertrend Multiplier", "Supertrend ATR multiplier", "Supertrend")
self._stochPeriod = self.Param("StochPeriod", 14) \
.SetDisplay("Stochastic Period", "Stochastic oscillator period", "Stochastic")
self._stochK = self.Param("StochK", 3) \
.SetDisplay("Stochastic %K", "Stochastic %K period", "Stochastic")
self._stochD = self.Param("StochD", 3) \
.SetDisplay("Stochastic %D", "Stochastic %D period", "Stochastic")
self._cooldownBars = self.Param("CooldownBars", 8) \
.SetRange(1, 50) \
.SetDisplay("Cooldown Bars", "Bars between trades", "General")
self._candleType = self.Param("CandleType", tf(5)) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._stopLossPercent = self.Param("StopLossPercent", 1.0) \
.SetDisplay("Stop Loss %", "Stop loss percentage from entry price", "Risk Management")
self._supertrend = None
self._stochastic = None
self._cooldown = 0
@property
def CandleType(self):
return self._candleType.Value
def OnReseted(self):
super(supertrend_stochastic_strategy, self).OnReseted()
self._supertrend = None
self._stochastic = None
self._cooldown = 0
def OnStarted2(self, time):
super(supertrend_stochastic_strategy, self).OnStarted2(time)
self._cooldown = 0
self._supertrend = SuperTrend()
self._supertrend.Length = self._supertrendPeriod.Value
self._supertrend.Multiplier = self._supertrendMultiplier.Value
self._stochastic = StochasticOscillator()
self._stochastic.K.Length = self._stochK.Value
self._stochastic.D.Length = self._stochD.Value
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(self._supertrend, self._stochastic, self.ProcessCandle).Start()
self.StartProtection(
takeProfit=Unit(2, UnitTypes.Percent),
stopLoss=Unit(self._stopLossPercent.Value, UnitTypes.Percent)
)
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._supertrend)
self.DrawOwnTrades(area)
def ProcessCandle(self, candle, st_result, stoch_result):
if candle.State != CandleStates.Finished:
return
if not self.IsFormedAndOnlineAndAllowTrading():
return
# Check SuperTrend value type
is_bullish = st_result.IsUpTrend
# Get stochastic K
stoch_k_val = stoch_result.K
if stoch_k_val is None:
return
stoch_k = float(stoch_k_val)
if self._cooldown > 0:
self._cooldown -= 1
return
if self.Position != 0:
return
# Buy: bullish supertrend + stochastic oversold area
if is_bullish and stoch_k < 30:
self.BuyMarket()
self._cooldown = int(self._cooldownBars.Value)
# Sell: bearish supertrend + stochastic overbought area
elif not is_bullish and stoch_k > 70:
self.SellMarket()
self._cooldown = int(self._cooldownBars.Value)
def CreateClone(self):
return supertrend_stochastic_strategy()