SuperTrend + EMA Rebound-Strategie
Das System handelt in Richtung des SuperTrend und sucht nach Pullbacks zu einem exponentiellen gleitenden Durchschnitt. Eine Position wird entweder eröffnet, wenn die SuperTrend-Linie die Richtung wechselt, oder wenn der Kurs von der EMA zurückprallt, während er im vorherrschenden SuperTrend-Bias verbleibt. Diese Kombination versucht, das erste Bein einer neuen Bewegung sowie anschließende Korrekturen innerhalb eines etablierten Trends zu erfassen.
Ein prozentuales Take Profit kann über das integrierte Schutzmodul aktiviert werden, indem der Take-Profit-Typ auf "%" gesetzt wird. Die Standardwerte bevorzugen Long- Trades, aber Short-Einstiege können ebenfalls aktiviert werden. Da die Strategie auf Richtungswechseln beruht, ist sie am effektivsten in Trendmärkten, wo SuperTrend schnell auf Momentum-Verschiebungen reagiert.
Details
- Einstiegskriterien:
- SuperTrend wechselt zum Aufwärtstrend, oder Kurs prallt über EMA bei Aufwärtstrend zurück.
- SuperTrend wechselt zum Abwärtstrend, oder Kurs prallt unter EMA bei Abwärtstrend zurück.
- Long/Short: Long standardmäßig aktiviert, Short optional.
- Ausstiegskriterien:
- Entgegengesetzter SuperTrend-Flip.
- Optionales Take Profit über das Schutzmodul.
- Stops: Prozentuales Take Profit über Schutz; kein Stop Loss enthalten.
- Standardwerte:
- ATR-Periode = 10, ATR-Faktor = 3.0.
- EMA-Länge = 20, TP = 1.5%.
- Filter:
- Kategorie: Trendfolge
- Richtung: Beide (Long Standard)
- Indikatoren: SuperTrend, EMA
- Stops: Optionaler TP
- Komplexität: Moderat
- Zeitrahmen: Kurz/mittel
- Saisonalität: Nein
- Neuronale Netze: Nein
- Divergenz: Nein
- Risikolevel: Mittel
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
/// <summary>
/// Supertrend + EMA Rebound Strategy.
/// Trades SuperTrend direction changes and EMA rebounds.
/// Buys when SuperTrend turns bullish or price rebounds from EMA in uptrend.
/// Sells when SuperTrend turns bearish or price rebounds from EMA in downtrend.
/// </summary>
public class SupertrendEmaReboundStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _atrFactor;
private readonly StrategyParam<int> _emaLength;
private readonly StrategyParam<int> _cooldownBars;
private SuperTrend _supertrend;
private ExponentialMovingAverage _ema;
private bool _prevIsUpTrend;
private bool _prevIsUpTrendSet;
private decimal _prevClose;
private decimal _prevEma;
private int _cooldownRemaining;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
public decimal AtrFactor
{
get => _atrFactor.Value;
set => _atrFactor.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public int CooldownBars
{
get => _cooldownBars.Value;
set => _cooldownBars.Value = value;
}
public SupertrendEmaReboundStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to use", "General");
_atrPeriod = Param(nameof(AtrPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR period for Supertrend", "Supertrend");
_atrFactor = Param(nameof(AtrFactor), 3.0m)
.SetDisplay("ATR Factor", "ATR factor for Supertrend", "Supertrend");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Moving Average");
_cooldownBars = Param(nameof(CooldownBars), 10)
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_supertrend = null;
_ema = null;
_prevIsUpTrend = false;
_prevIsUpTrendSet = false;
_prevClose = 0;
_prevEma = 0;
_cooldownRemaining = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_supertrend = new SuperTrend { Length = AtrPeriod, Multiplier = AtrFactor };
_ema = new ExponentialMovingAverage { Length = EmaLength };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(_supertrend, _ema, OnProcess)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _supertrend);
DrawIndicator(area, _ema);
DrawOwnTrades(area);
}
}
private void OnProcess(ICandleMessage candle, IIndicatorValue stValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_supertrend.IsFormed || !_ema.IsFormed)
return;
if (stValue.IsEmpty || emaValue.IsEmpty)
return;
var stTyped = (SuperTrendIndicatorValue)stValue;
var isUpTrend = stTyped.IsUpTrend;
var emaVal = emaValue.ToDecimal();
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevIsUpTrend = isUpTrend;
_prevIsUpTrendSet = true;
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
if (_cooldownRemaining > 0)
{
_cooldownRemaining--;
_prevIsUpTrend = isUpTrend;
_prevIsUpTrendSet = true;
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
if (!_prevIsUpTrendSet || _prevClose == 0)
{
_prevIsUpTrend = isUpTrend;
_prevIsUpTrendSet = true;
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
return;
}
// SuperTrend direction change
var trendTurnedUp = isUpTrend && !_prevIsUpTrend;
var trendTurnedDown = !isUpTrend && _prevIsUpTrend;
// EMA rebound: price was below EMA and now crosses above
var emaReboundUp = isUpTrend && _prevClose < _prevEma && candle.ClosePrice > emaVal;
// EMA rebound: price was above EMA and now crosses below
var emaReboundDown = !isUpTrend && _prevClose > _prevEma && candle.ClosePrice < emaVal;
// Buy: SuperTrend turns bullish or EMA rebound up in uptrend
if ((trendTurnedUp || emaReboundUp) && Position <= 0)
{
if (Position < 0)
BuyMarket(Math.Abs(Position));
BuyMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Sell: SuperTrend turns bearish or EMA rebound down in downtrend
else if ((trendTurnedDown || emaReboundDown) && Position >= 0)
{
if (Position > 0)
SellMarket(Math.Abs(Position));
SellMarket(Volume);
_cooldownRemaining = CooldownBars;
}
// Exit long on SuperTrend bearish flip
else if (Position > 0 && trendTurnedDown)
{
SellMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
// Exit short on SuperTrend bullish flip
else if (Position < 0 && trendTurnedUp)
{
BuyMarket(Math.Abs(Position));
_cooldownRemaining = CooldownBars;
}
_prevIsUpTrend = isUpTrend;
_prevIsUpTrendSet = true;
_prevClose = candle.ClosePrice;
_prevEma = emaVal;
}
}
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 SuperTrend, ExponentialMovingAverage, IndicatorHelper
from StockSharp.Algo.Strategies import Strategy
class supertrend_ema_rebound_strategy(Strategy):
"""Supertrend + EMA Rebound Strategy."""
def __init__(self):
super(supertrend_ema_rebound_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30))) \
.SetDisplay("Candle Type", "Type of candles to use", "General")
self._atr_period = self.Param("AtrPeriod", 10) \
.SetDisplay("ATR Period", "ATR period for Supertrend", "Supertrend")
self._atr_factor = self.Param("AtrFactor", 3.0) \
.SetDisplay("ATR Factor", "ATR factor for Supertrend", "Supertrend")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Moving Average")
self._cooldown_bars = self.Param("CooldownBars", 10) \
.SetDisplay("Cooldown Bars", "Bars to wait between trades", "Risk")
self._supertrend = None
self._ema = None
self._prev_is_up_trend = False
self._prev_is_up_trend_set = False
self._prev_close = 0.0
self._prev_ema = 0.0
self._cooldown_remaining = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(supertrend_ema_rebound_strategy, self).OnReseted()
self._supertrend = None
self._ema = None
self._prev_is_up_trend = False
self._prev_is_up_trend_set = False
self._prev_close = 0.0
self._prev_ema = 0.0
self._cooldown_remaining = 0
def OnStarted2(self, time):
super(supertrend_ema_rebound_strategy, self).OnStarted2(time)
self._supertrend = SuperTrend()
self._supertrend.Length = int(self._atr_period.Value)
self._supertrend.Multiplier = float(self._atr_factor.Value)
self._ema = ExponentialMovingAverage()
self._ema.Length = int(self._ema_length.Value)
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(self._supertrend, self._ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, self._supertrend)
self.DrawIndicator(area, self._ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, st_value, ema_value):
if candle.State != CandleStates.Finished:
return
if not self._supertrend.IsFormed or not self._ema.IsFormed:
return
if st_value.IsEmpty or ema_value.IsEmpty:
return
is_up_trend = st_value.IsUpTrend
ema_val = float(IndicatorHelper.ToDecimal(ema_value))
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_is_up_trend = is_up_trend
self._prev_is_up_trend_set = True
self._prev_close = float(candle.ClosePrice)
self._prev_ema = ema_val
return
if self._cooldown_remaining > 0:
self._cooldown_remaining -= 1
self._prev_is_up_trend = is_up_trend
self._prev_is_up_trend_set = True
self._prev_close = float(candle.ClosePrice)
self._prev_ema = ema_val
return
if not self._prev_is_up_trend_set or self._prev_close == 0.0:
self._prev_is_up_trend = is_up_trend
self._prev_is_up_trend_set = True
self._prev_close = float(candle.ClosePrice)
self._prev_ema = ema_val
return
close = float(candle.ClosePrice)
cooldown = int(self._cooldown_bars.Value)
trend_turned_up = is_up_trend and not self._prev_is_up_trend
trend_turned_down = not is_up_trend and self._prev_is_up_trend
ema_rebound_up = is_up_trend and self._prev_close < self._prev_ema and close > ema_val
ema_rebound_down = not is_up_trend and self._prev_close > self._prev_ema and close < ema_val
if (trend_turned_up or ema_rebound_up) and self.Position <= 0:
if self.Position < 0:
self.BuyMarket(Math.Abs(self.Position))
self.BuyMarket(self.Volume)
self._cooldown_remaining = cooldown
elif (trend_turned_down or ema_rebound_down) and self.Position >= 0:
if self.Position > 0:
self.SellMarket(Math.Abs(self.Position))
self.SellMarket(self.Volume)
self._cooldown_remaining = cooldown
elif self.Position > 0 and trend_turned_down:
self.SellMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
elif self.Position < 0 and trend_turned_up:
self.BuyMarket(Math.Abs(self.Position))
self._cooldown_remaining = cooldown
self._prev_is_up_trend = is_up_trend
self._prev_is_up_trend_set = True
self._prev_close = close
self._prev_ema = ema_val
def CreateClone(self):
return supertrend_ema_rebound_strategy()