Reverse Strategy ist ein Mean-Reversion-Handelssystem, das Bollinger-Bänder und den Relative Strength Index (RSI) kombiniert, um erschöpfte Bewegungen zu identifizieren. Die Strategie sucht nach Preisumkehrungen in der Nähe der Bollinger-Umschläge und erfordert gleichzeitig, dass der RSI aus einer überverkauften oder überkauften Zone zurückkehrt. Sobald beide Bedingungen erfüllt sind, beginnt die Strategie gegen die vorherige Bewegung und verwaltet Geschäfte mit festen, bandbasierten Stopps und Zielen.
Handelslogik
Abonnieren Sie die konfigurierte Kerzenserie (Standard-5-Minuten-Kerzen).
Berechnen Sie Bollinger-Bänder mithilfe eines einfachen gleitenden Durchschnitts mit der konfigurierten Periode und dem Abweichungsmultiplikator.
Berechnen Sie RSI mithilfe des konfigurierten Lookback-Zeitraums.
Verfolgen Sie die zuvor abgeschlossene Kerze, um Überkreuzungen zu erkennen:
Long Setup: Der vorherige Schlusskurs liegt unter dem vorherigen unteren Band und RSI liegt unter dem überverkauften Schwellenwert. Der aktuelle Schlusskurs muss wieder über das untere Band steigen, während RSI über das überverkaufte Niveau steigt.
Short-Setup: Der vorherige Schlusskurs liegt über dem vorherigen oberen Band und RSI liegt über dem überkauften Schwellenwert. Der aktuelle Schlusskurs muss wieder unter das obere Band fallen, während RSI unter das überkaufte Niveau fällt.
Wenn ein Long-Setup ausgelöst wird, kaufen Sie zum Marktwert, setzen Sie einen Schutzstopp eine Standardabweichung unter dem Einstiegsschluss und einen Take-Profit zwei Standardabweichungen darüber.
Wenn ein Short-Setup ausgelöst wird, verkaufen Sie zum Marktwert, setzen Sie einen Schutzstopp eine Standardabweichung über dem Einstiegsschluss und einen Take-Profit zwei Standardabweichungen darunter.
Offene Stellen verwalten:
Schließen Sie Long-Trades, wenn der Preis das obere Band berührt, den Stop erreicht oder das Take-Profit-Ziel erreicht.
Schließen Sie Short-Trades, wenn der Preis das untere Band berührt, den Stop erreicht oder das Take-Profit-Ziel erreicht.
Parameter
Name
Beschreibung
Standard
CandleType
Zeitrahmen für das Kerzenabonnement.
Zeitrahmen von 5 Minuten
BollingerPeriod
Anzahl der Balken, die für den gleitenden Durchschnitt Bollinger und die Standardabweichung verwendet werden.
20
BollingerWidth
Standardabweichungsmultiplikator, angewendet auf Bollinger Bänder.
2,0
RsiPeriod
Anzahl der Balken, die zur Berechnung des RSI verwendet werden.
14
RsiOverbought
RSI Schwellenwert, der überkaufte Bedingungen für Short-Einstiege signalisiert.
70
RsiOversold
RSI Schwellenwert signalisiert überverkaufte Bedingungen für lange Einträge.
30
Alle Parameter unterstützen die Optimierung über den StockSharp Designer oder Runner. Durch Anpassen der Überverkauft-/Überkauft-Werte ändert sich, wie aggressiv die Umkehrerkennung ist, während die Bollinger-Breite steuert, wie weit sich der Preis ausdehnen muss, bevor Signale berücksichtigt werden.
Nutzungshinweise
Die Strategie verwendet das High-Level StockSharp API mit automatischen Kerzenabonnements und Indikatorbindung.
Alle Handelsvorgänge basieren auf Marktaufträgen (BuyMarket/SellMarket). Stop-Loss- und Take-Profit-Level werden im Code und nicht als ausstehende Aufträge verarbeitet.
Die Standardkonfiguration zielt auf größere Umkehrungen auf Intraday-Charts ab, kann jedoch durch Änderung von CandleType an längere Zeitrahmen angepasst werden.
Erwägen Sie die Kombination der Strategie mit zusätzlichen Filtern (Trend, Volatilität, Sitzungszeit), wenn Sie sie in Live-Umgebungen ausführen.
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Simplified from "Reverse" MetaTrader expert.
/// Uses Bollinger Band touches with RSI confirmation for mean-reversion entries.
/// Enters long when price crosses above lower band with RSI oversold,
/// enters short when price crosses below upper band with RSI overbought.
/// </summary>
public class ReverseStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _bollingerPeriod;
private readonly StrategyParam<decimal> _bollingerWidth;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _rsiOverbought;
private readonly StrategyParam<decimal> _rsiOversold;
private ExponentialMovingAverage _ema;
private RelativeStrengthIndex _rsi;
private decimal _prevClose;
private decimal _prevRsi;
private decimal _prevLower;
private decimal _prevUpper;
private bool _hasPrev;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int BollingerPeriod
{
get => _bollingerPeriod.Value;
set => _bollingerPeriod.Value = value;
}
public decimal BollingerWidth
{
get => _bollingerWidth.Value;
set => _bollingerWidth.Value = value;
}
public int RsiPeriod
{
get => _rsiPeriod.Value;
set => _rsiPeriod.Value = value;
}
public decimal RsiOverbought
{
get => _rsiOverbought.Value;
set => _rsiOverbought.Value = value;
}
public decimal RsiOversold
{
get => _rsiOversold.Value;
set => _rsiOversold.Value = value;
}
public ReverseStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for signals", "General");
_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Bollinger Period", "MA length for Bollinger Bands", "Indicators");
_bollingerWidth = Param(nameof(BollingerWidth), 1m)
.SetGreaterThanZero()
.SetDisplay("Bollinger Width", "Standard deviation multiplier", "Indicators");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_rsiOverbought = Param(nameof(RsiOverbought), 70m)
.SetDisplay("RSI Overbought", "Upper threshold for short signals", "Signals");
_rsiOversold = Param(nameof(RsiOversold), 30m)
.SetDisplay("RSI Oversold", "Lower threshold for long signals", "Signals");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_ema = new ExponentialMovingAverage { Length = BollingerPeriod };
_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
_hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(_ema, _rsi, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _ema);
DrawIndicator(area, _rsi);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal emaValue, decimal rsiValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_ema.IsFormed || !_rsi.IsFormed)
return;
var close = candle.ClosePrice;
var bandOffset = emaValue * (BollingerWidth / 100m);
var upperBand = emaValue + bandOffset;
var lowerBand = emaValue - bandOffset;
if (!_hasPrev)
{
_prevClose = close;
_prevRsi = rsiValue;
_prevLower = lowerBand;
_prevUpper = upperBand;
_hasPrev = true;
return;
}
var volume = Volume;
if (volume <= 0)
volume = 1;
// Long: price crosses up from below lower band + RSI was oversold
var longSignal = _prevClose < _prevLower && close >= lowerBand && _prevRsi < RsiOversold;
// Short: price crosses down from above upper band + RSI was overbought
var shortSignal = _prevClose > _prevUpper && close <= upperBand && _prevRsi > RsiOverbought;
if (longSignal)
{
if (Position <= 0)
BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
}
else if (shortSignal)
{
if (Position >= 0)
SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
}
// Exit long at upper band
if (Position > 0 && close >= upperBand)
SellMarket(Position);
// Exit short at lower band
if (Position < 0 && close <= lowerBand)
BuyMarket(Math.Abs(Position));
_prevClose = close;
_prevRsi = rsiValue;
_prevLower = lowerBand;
_prevUpper = upperBand;
}
/// <inheritdoc />
protected override void OnReseted()
{
_ema = null;
_rsi = null;
_prevClose = 0;
_prevRsi = 0;
_prevLower = 0;
_prevUpper = 0;
_hasPrev = false;
base.OnReseted();
}
}
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 ExponentialMovingAverage, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class reverse_strategy(Strategy):
def __init__(self):
super(reverse_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._bollinger_period = self.Param("BollingerPeriod", 20)
self._bollinger_width = self.Param("BollingerWidth", 1.0)
self._rsi_period = self.Param("RsiPeriod", 14)
self._rsi_overbought = self.Param("RsiOverbought", 70.0)
self._rsi_oversold = self.Param("RsiOversold", 30.0)
self._prev_close = 0.0
self._prev_rsi = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def BollingerPeriod(self):
return self._bollinger_period.Value
@BollingerPeriod.setter
def BollingerPeriod(self, value):
self._bollinger_period.Value = value
@property
def BollingerWidth(self):
return self._bollinger_width.Value
@BollingerWidth.setter
def BollingerWidth(self, value):
self._bollinger_width.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def RsiOverbought(self):
return self._rsi_overbought.Value
@RsiOverbought.setter
def RsiOverbought(self, value):
self._rsi_overbought.Value = value
@property
def RsiOversold(self):
return self._rsi_oversold.Value
@RsiOversold.setter
def RsiOversold(self, value):
self._rsi_oversold.Value = value
def OnReseted(self):
super(reverse_strategy, self).OnReseted()
self._prev_close = 0.0
self._prev_rsi = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(reverse_strategy, self).OnStarted2(time)
self._prev_close = 0.0
self._prev_rsi = 0.0
self._prev_lower = 0.0
self._prev_upper = 0.0
self._has_prev = False
ema = ExponentialMovingAverage()
ema.Length = self.BollingerPeriod
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema, rsi, self._process_candle).Start()
def _process_candle(self, candle, ema_value, rsi_value):
if candle.State != CandleStates.Finished:
return
ema_val = float(ema_value)
rsi_val = float(rsi_value)
close = float(candle.ClosePrice)
band_offset = ema_val * (float(self.BollingerWidth) / 100.0)
upper_band = ema_val + band_offset
lower_band = ema_val - band_offset
if not self._has_prev:
self._prev_close = close
self._prev_rsi = rsi_val
self._prev_lower = lower_band
self._prev_upper = upper_band
self._has_prev = True
return
# Long: price crosses up from below lower band + RSI was oversold
long_signal = (self._prev_close < self._prev_lower and close >= lower_band and
self._prev_rsi < float(self.RsiOversold))
# Short: price crosses down from above upper band + RSI was overbought
short_signal = (self._prev_close > self._prev_upper and close <= upper_band and
self._prev_rsi > float(self.RsiOverbought))
if long_signal:
if self.Position <= 0:
self.BuyMarket()
elif short_signal:
if self.Position >= 0:
self.SellMarket()
# Exit long at upper band
if self.Position > 0 and close >= upper_band:
self.SellMarket()
# Exit short at lower band
if self.Position < 0 and close <= lower_band:
self.BuyMarket()
self._prev_close = close
self._prev_rsi = rsi_val
self._prev_lower = lower_band
self._prev_upper = upper_band
def CreateClone(self):
return reverse_strategy()