Die ABE BE RSI-Strategie ist eine Portierung des MetaTrader-Expertenberaters Expert_ABE_BE_RSI. Das System kombiniert klassische Candlestick-Umkehrmuster mit der Momentum-Bestätigung durch den Relative Strength Index (RSI). Zwei aufeinanderfolgende Kerzen müssen ein bullisches oder bärisches Engulfing-Muster bilden, und die zuletzt abgeschlossene Kerze muss einen RSI-Wert innerhalb vordefinierter Schwellenwerte aufweisen. Zusätzliche RSI-Kreuzregeln werden angewendet, um bestehende Positionen abzuflachen oder umzukehren, was die Entscheidungslogik der ursprünglichen MQL-Implementierung weitgehend widerspiegelt.
Handelslogik
Erkennung verschlingender Muster
Die Strategie bewertet die beiden zuletzt abgeschlossenen Kerzen. Ein bullisches Signal erfordert:
Kerze t-2 schließt tiefer als sie öffnet (bärischer Körper).
Kerze t-1 schließt höher als sie öffnet (bullischer Körper).
Die Körpergröße der Kerze t-1 übersteigt den gleitenden Durchschnitt der jüngsten Körpergrößen (Standard: fünf Balken).
Kerze t-1 schließt über dem Eröffnungskurs von Kerze t-2 und öffnet unter ihrem Schlusskurs, was ein echtes Engulfing-Ereignis gewährleistet.
Der Mittelpunkt der Kerze t-2 liegt unter dem gleitenden Durchschnitt der Schlusskurse, was einen kurzfristigen Abwärtstrend bestätigt.
Ein bärisches Engulfing-Signal nutzt die symmetrischen Bedingungen: Die ältere Kerze ist bullisch, die neuere Kerze ist bärisch mit einem überdurchschnittlich großen Körper und die neuere Kerze umhüllt den vorherigen Körper vollständig, während der Mittelpunkt des älteren Balkens über dem gleitenden Durchschnitt liegt, um eine Erschöpfung des Abwärtstrends zu bestätigen.
RSI Bestätigung
Für Long-Einträge muss der RSI der zuletzt geschlossenen Kerze unter dem konfigurierten bullischen Einstiegsniveau liegen (Standard 40).
Für Short-Einstiege muss der RSI der zuletzt geschlossenen Kerze über dem rückläufigen Einstiegsniveau liegen (Standard 60).
Exit-Management
RSI Crossovers über zwei Ebenen werden überwacht, um bestehende Positionen zu schließen:
Short-Positionen werden gedeckt, wenn RSI entweder über die untere (Standard 30) oder obere (Standard 70) Ausstiegsschwelle steigt, nachdem sie bei der vorherigen Kerze darunter lag.
Long-Positionen werden geschlossen, wenn RSI unter einen der Schwellenwerte fällt, nachdem er bei der vorherigen Kerze darüber lag.
Auftragsausführung
Marktaufträge werden sowohl für Ein- als auch für Ausstiege verwendet. Bei der Umkehrung schließt die Strategie zunächst das aktuelle Exposure und steigt dann in die neue Richtung mit dem konfigurierten Basisvolumen ein. Die Positionsgrößenbestimmung ahmt das Fixed-Lot-Modell des MQL-Experten nach.
Parameter
Name
Beschreibung
Standard
Volume
Auftragsgröße in Verträgen.
0.1
RsiPeriod
Anzahl der vom RSI-Filter verwendeten Balken.
11
MovingAveragePeriod
Zeitraum für die Größe des Kerzenkörpers und die gleitenden Durchschnitte des Schlusskurses.
5
BullishEntryLevel
Maximaler RSI-Wert, der immer noch einen bullischen Engulfing-Einstieg bestätigt.
40
BearishEntryLevel
Mindestwert RSI erforderlich für einen bärischen Engulfing-Einstieg.
60
ExitLowerLevel
Unteres Kreuzungsniveau RSI für Abflachungspositionen.
30
ExitUpperLevel
Oberes Kreuzungsniveau RSI für Abflachungspositionen.
70
CandleType
Von der Strategie verarbeitete Kerzenserie.
1 hour time frame
Dank der StrategyParam-Wrapper können alle Parameter innerhalb von Designer oder Runner optimiert werden.
Indikatorpipeline
Relative Strength Index (RSI) – berechnet die Dynamik über den konfigurierbaren RsiPeriod und liefert Einstiegs-/Ausstiegsschwellen.
Einfacher gleitender Durchschnitt der Schlusskurse – bietet einen Trendkontext zur Validierung verschlingender Muster.
Einfacher gleitender Durchschnitt der Kerzenkörpergrößen – stellt sicher, dass die umschließende Kerze größer ist als die durchschnittliche Körpergröße der letzten MovingAveragePeriod Balken.
Nutzungshinweise
Die Strategie wirkt nur auf vollständig abgeschlossene Kerzen (CandleStates.Finished). Teilbalkendaten werden ignoriert, um vorzeitige Signale zu vermeiden.
Der Kerzenverlauf wird intern gespeichert, um Engulfing-Bedingungen zu bewerten, ohne große Sammlungen zu durchlaufen, und dabei die projektweiten Konvertierungsrichtlinien zu berücksichtigen.
StartProtection() ist aktiviert, sodass die grundlegenden StockSharp-Schutzmechanismen aktiv werden, wenn die Positionsexposition ungleich Null ist.
Unterschiede zum ursprünglichen Expert Advisor
Der ursprüngliche Expert Advisor basiert auf dem Signal-Voting-System von MetaTrader. In diesem Port werden die Stimmen in direkte Ein- und Austrittsaktionen umgesetzt, die dieselben Bedingungen nachbilden.
Die Geldverwaltung wird auf einen einzigen Volume-Parameter vereinfacht, der die vom Quellenexperten verwendete feste Losgröße (Money_FixLot_Lots) widerspiegelt.
Trailing-Stop-Unterstützung ist nicht enthalten, da die MT5-Version ein „No Trailing“-Modul verwendet.
Empfohlene Tests
Hängen Sie die Strategie an ein Diagramm in Designer oder API Runner mit einem Symbol an, das in der Vergangenheit auf umfassende Umkehrungen (z. B. große FX-Paare) reagiert.
Überprüfen Sie die Parameter RSI und gleitenden Durchschnitt, bevor Sie Live-Sitzungen ausführen. Die Standardeinstellungen reproduzieren die veröffentlichten Expert Advisor-Einstellungen.
Nutzen Sie die integrierten Optimierungsfunktionen, um alternative RSI-Schwellenwerte oder Durchschnittszeiträume für verschiedene Märkte zu erkunden.
namespace StockSharp.Samples.Strategies;
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// ABE BE RSI strategy: Engulfing pattern with RSI confirmation.
/// Bullish engulfing + oversold RSI for long, bearish engulfing + overbought RSI for short.
/// </summary>
public class AbeBeRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private readonly StrategyParam<decimal> _oversold;
private readonly StrategyParam<decimal> _overbought;
private readonly StrategyParam<int> _signalCooldownCandles;
private readonly List<ICandleMessage> _candles = new();
private int _candlesSinceTrade;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }
public AbeBeRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
_oversold = Param(nameof(Oversold), 40m)
.SetDisplay("Oversold", "RSI oversold level", "Signals");
_overbought = Param(nameof(Overbought), 60m)
.SetDisplay("Overbought", "RSI overbought level", "Signals");
_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 6)
.SetGreaterThanZero()
.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_candles.Clear();
_candlesSinceTrade = SignalCooldownCandles;
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, decimal rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (_candlesSinceTrade < SignalCooldownCandles)
_candlesSinceTrade++;
_candles.Add(candle);
if (_candles.Count > 5)
_candles.RemoveAt(0);
if (_candles.Count >= 2)
{
var curr = _candles[^1];
var prev = _candles[^2];
var bullishEngulfing = prev.OpenPrice > prev.ClosePrice
&& curr.ClosePrice > curr.OpenPrice
&& curr.OpenPrice <= prev.ClosePrice
&& curr.ClosePrice >= prev.OpenPrice;
var bearishEngulfing = prev.ClosePrice > prev.OpenPrice
&& curr.OpenPrice > curr.ClosePrice
&& curr.OpenPrice >= prev.ClosePrice
&& curr.ClosePrice <= prev.OpenPrice;
if (bullishEngulfing && rsiValue < Oversold && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
BuyMarket();
_candlesSinceTrade = 0;
}
else if (bearishEngulfing && rsiValue > Overbought && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
{
SellMarket();
_candlesSinceTrade = 0;
}
}
}
}
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 RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class abe_be_rsi_strategy(Strategy):
def __init__(self):
super(abe_be_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(30)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._oversold = self.Param("Oversold", 40.0)
self._overbought = self.Param("Overbought", 60.0)
self._signal_cooldown_candles = self.Param("SignalCooldownCandles", 6)
self._candles = []
self._candles_since_trade = 6
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
@property
def Oversold(self):
return self._oversold.Value
@Oversold.setter
def Oversold(self, value):
self._oversold.Value = value
@property
def Overbought(self):
return self._overbought.Value
@Overbought.setter
def Overbought(self, value):
self._overbought.Value = value
@property
def SignalCooldownCandles(self):
return self._signal_cooldown_candles.Value
@SignalCooldownCandles.setter
def SignalCooldownCandles(self, value):
self._signal_cooldown_candles.Value = value
def OnReseted(self):
super(abe_be_rsi_strategy, self).OnReseted()
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
def OnStarted2(self, time):
super(abe_be_rsi_strategy, self).OnStarted2(time)
self._candles.clear()
self._candles_since_trade = self.SignalCooldownCandles
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(rsi, self._process_candle).Start()
def _process_candle(self, candle, rsi_value):
if candle.State != CandleStates.Finished:
return
if self._candles_since_trade < self.SignalCooldownCandles:
self._candles_since_trade += 1
rsi_val = float(rsi_value)
self._candles.append(candle)
if len(self._candles) > 5:
self._candles.pop(0)
if len(self._candles) >= 2:
curr = self._candles[-1]
prev = self._candles[-2]
bullish_engulfing = (float(prev.OpenPrice) > float(prev.ClosePrice)
and float(curr.ClosePrice) > float(curr.OpenPrice)
and float(curr.OpenPrice) <= float(prev.ClosePrice)
and float(curr.ClosePrice) >= float(prev.OpenPrice))
bearish_engulfing = (float(prev.ClosePrice) > float(prev.OpenPrice)
and float(curr.OpenPrice) > float(curr.ClosePrice)
and float(curr.OpenPrice) >= float(prev.ClosePrice)
and float(curr.ClosePrice) <= float(prev.OpenPrice))
if bullish_engulfing and rsi_val < self.Oversold and self.Position <= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.BuyMarket()
self._candles_since_trade = 0
elif bearish_engulfing and rsi_val > self.Overbought and self.Position >= 0 and self._candles_since_trade >= self.SignalCooldownCandles:
self.SellMarket()
self._candles_since_trade = 0
def CreateClone(self):
return abe_be_rsi_strategy()