Diese Strategie ist ein StockSharp-Port des MetaTrader 5-Expertenberaters "RSI EA v2". Sie automatisiert den Handel rund um Relative Strength Index (RSI)-Schwellenwert-Kreuzungen und spiegelt die Money-Management-, Trailing-Stop- und Handelszeit-Kontrollen des ursprünglichen Beraters wider. Standardmäßig verarbeitet die Strategie Einminuten-Kerzen, aber jeder Kerzentyp kann über Parameter angegeben werden.
Handelslogik
Eintrittsbedingungen
Long-Positionen öffnen sich, wenn RSI über den konfigurierten Kauflevel steigt, nachdem er auf der vorherigen abgeschlossenen Kerze darunter lag, und die Handelsstunden neue Orders erlauben.
Short-Positionen öffnen sich, wenn RSI unter den konfigurierten Verkauflevel fällt, nachdem er zuvor darüber war, und das Handelsfenster offen ist.
Wenn bereits eine entgegengesetzte Position existiert, dimensioniert die Strategie die neue Marktorder so, dass sie die aktuelle Exposition flattened und die gewünschte Richtung etabliert (nur Nettopositionen).
Austrittsbedingungen
Stop-Loss- und Take-Profit-Niveaus in Pips werden angehängt, sobald eine neue Position erkannt wird.
Ein Trailing-Stop spiegelt den ursprünglichen EA wider: aktiviert sich nach Trailing-Stop + Trailing-Schritt Preisfortschritt und bewegt sich dann um mindestens den Trailing-Schritt.
Optionale „Close by Signal"-Logik schließt Long-Positionen, wenn RSI nach unten durch den Verkauflevel kreuzt, und schließt Short-Positionen, wenn RSI nach oben durch den Kauflevel kreuzt.
Stops und Signale werden nur auf abgeschlossenen Kerzen ausgewertet, was das Verhalten in Backtests deterministisch hält.
Risiko- und Trade-Management
Stop-Loss / Take-Profit – in Pips definiert, in Preisschritte umgerechnet, die die Instrumentenpräzision respektieren (einschließlich 3/5-Stellen-Forex-Symbole).
Trailing-Stop – deaktiviert wenn Abstand null ist. Ein positiver Trailing-Schritt ist erforderlich, wenn der Trailing-Abstand ungleich null ist.
Positionsgröße – entweder ein festes Volumen oder ein automatisches Volumen aus Risikoprozentsatz und Stop-Abstand berechnet. Risiko-Sizing erfordert Zugang zu Portfolio-Eigenkapital und validen Preisschritt-Metadaten.
Handelsfenster – optionaler täglicher Filter durch inklusive Start- und exklusive End-Stunden (0–23). Wenn Start gleich End ist, gilt der Markt als geschlossen.
Parameter
Name
Beschreibung
OpenBuy / OpenSell
Schaltet Long- oder Short-Eintritte unabhängig ein/aus.
CloseBySignal
Aktiviert Ausstiege bei entgegengesetzten RSI-Kreuzungen.
StopLossPips
Stop-Loss-Abstand in Pips (0 deaktiviert den Stop).
TakeProfitPips
Take-Profit-Abstand in Pips (0 deaktiviert das Ziel).
TrailingStopPips
Trailing-Stop-Abstand in Pips. Muss null sein, wenn kein Trailing gewünscht.
TrailingStepPips
Zusätzlicher Fortschritt (in Pips) vor dem Verschieben des Trailing-Stops. Muss positiv sein, wenn Trailing aktiv.
RsiPeriod
RSI-Indikatorlänge.
RsiBuyLevel / RsiSellLevel
Schwellenwerte für Long- und Short-Eintritte/Ausstiege.
UseRiskSizing
Wechselt zwischen festem Volumen und risikoprozentualer Positionsgröße.
FixedVolume
Basis-Ordergröße für Fixvolumen-Modus oder Fallback wenn Risiko-Sizing nicht berechnet werden kann.
RiskPercent
Prozentsatz des Portfolio-Eigenkapitals pro Trade. Nur wenn UseRiskSizing wahr ist und positiver Stop-Abstand vorhanden.
UseTimeControl
Aktiviert den täglichen Handelsfensterfilter.
StartHour / EndHour
Inklusive Start- und exklusive End-Stunde (0–23) des Handelsfensters.
CandleType
Kerzen-Datentyp für Indikatorberechnungen.
Implementierungshinweise
Verwendet die High-Level-Kerzen-Abonnement-API mit RSI-Indikator-Binding.
Konvertiert Pip-Abstände mithilfe der Instrumentenpräzision (PriceStep und Decimals), um MetaTrader's 3/5-Stellen-Logik zu entsprechen.
Normalisiert Ordervolumen auf den Volumen-Step und die Grenzen des Instruments (Min/Max-Volumen).
Trailing-Logik aktualisiert nur interne Stop-Referenzen; Ausstiege werden mit Marktorders durchgeführt, wenn Niveaus verletzt werden.
Hält separaten Zustand für Long- und Short-Positionen, um Trailing- und Schutzniveaus zwischen Kerzen zu erhalten.
Verwendung
Hängen Sie die Strategie an einen StockSharp-Connector mit geeigneten Instrument- und Portfolio-Metadaten.
Konfigurieren Sie Schwellenwerte, Pip-Abstände und optionales Zeitfenster für den gewünschten Markt.
Aktivieren Sie risikobasiertes Sizing wenn Portfolio-Informationen verfügbar sind; andernfalls deaktiviert lassen für ein festes Lot.
Starten Sie die Strategie – sie wartet auf abgeschlossene Kerzen, wendet die RSI-Logik an und verwaltet aktive Positionen gemäß den konfigurierten Schutzmechanismen.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// RSI EA v2 strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class RsiEaV2Strategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public RsiEaV2Strategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class rsi_ea_v2_strategy(Strategy):
def __init__(self):
super(rsi_ea_v2_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(rsi_ea_v2_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(rsi_ea_v2_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return rsi_ea_v2_strategy()