Diese Strategie ist eine StockSharp-Portierung des MetaTrader 5-Expertenberaters e_RP_250. Das ursprüngliche System handelt Umkehrungen, die von einem benutzerdefinierten rPoint-Indikator erkannt werden. Da dieser Indikator in StockSharp nicht verfügbar ist, recreiert die Konvertierung dasselbe Verhalten mit rollierenden Höchst- und Tiefstkurs-Trackern. Wenn ein neues Swing-Hoch oder Swing-Tief erscheint, kehrt die Strategie die Position um und fügt dieselbe Stop-Loss-, Take-Profit- und optionale Trailing-Logik wie die MQL-Version hinzu.
Der ursprüngliche Quellcode hat keine verifizierten Performance-Ergebnisse veröffentlicht, daher sollten Sie vor dem Einsatz der Strategie im Produktionsbetrieb Ihre eigene Bewertung durchführen.
Handelslogik
Abonnierung von Kerzen, die durch den Parameter CandleType definiert werden (standardmäßig 5-Minuten-Kerzen).
Verfolgung des höchsten Hochs und niedrigsten Tiefs über die letzten ReversePoint Bars (standardmäßig 250).
Wenn die aktuelle Kerze ein neues höchstes Hoch setzt, Long-Position schließen und Short-Position eröffnen.
Wenn die aktuelle Kerze ein neues niedrigstes Tief setzt, Short-Position schließen und Long-Position eröffnen.
Schützende Stop-Loss- und Take-Profit-Level werden in Preispunkten ausgedrückt und durch StartProtection reproduziert.
Optionale Trailing-Stops sichern Gewinne, sobald der Preis die konfigurierte Anzahl an Punkten bewegt.
Zu jedem Zeitpunkt ist nur eine Position aktiv. Die Strategie blockiert auch doppelte Orders während derselben Kerze, indem sie sich die letzte Ausführungszeit merkt und damit die TimeN-Schutzmaßnahme aus dem MQL-Skript repliziert.
Parameter
Parameter
Beschreibung
TakeProfitPoints
Abstand in Preispunkten für die Take-Profit-Order (Standard 15). Auf null setzen, um die automatische Gewinnmitnahme zu deaktivieren.
StopLossPoints
Abstand in Preispunkten für die Stop-Loss-Order (Standard 999). Auf null setzen, um ohne festen Stop zu handeln.
TrailingStopPoints
Optionaler Trailing-Stop-Abstand in Preispunkten (Standard 0 deaktiviert die Trailing-Logik).
ReversePoint
Anzahl der Kerzen zur Erkennung von Umkehrpunkten. Größere Werte reagieren langsamer, filtern aber Rauschen heraus.
CandleType
Zu analysierende Kerzen-Aggregation. Standard ist ein 5-Minuten-Zeitrahmen, kann aber auf jeden DataType geändert werden.
Positionsverwaltung
StartProtection wendet dieselben Stop-Loss- und Take-Profit-Abstände wie der MT5-Experte an.
Der Trailing-Stop verfolgt den günstigsten Preis nach dem Einstieg und schließt die Position, wenn der Preis um den konfigurierten Betrag zurückkehrt.
Umkehrsignale von der entgegengesetzten Seite schließen sofort die aktuelle Position, bevor eine neue eröffnet wird.
Verwendungshinweise
Stellen Sie sicher, dass die Datenquelle den ausgewählten Kerzentyp unterstützt, andernfalls werden keine Signale generiert.
Die Strategie ist auf Dezimalpreise angewiesen. Überprüfen Sie, dass die PriceStep-Eigenschaft des Wertpapiers den Punktwert korrekt widerspiegelt.
Testen Sie verschiedene ReversePoint-Werte, um die Ausbruchsempfindlichkeit an die Volatilität des gehandelten Instruments anzupassen.
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>
/// Reverse point breakout strategy converted from the e_RP_250 MQL script.
/// </summary>
public class ERp250Strategy : Strategy
{
private readonly StrategyParam<decimal> _takeProfitPoints;
private readonly StrategyParam<decimal> _stopLossPoints;
private readonly StrategyParam<decimal> _trailingStopPoints;
private readonly StrategyParam<int> _reversePoint;
private readonly StrategyParam<DataType> _candleType;
private Highest _highest;
private Lowest _lowest;
private decimal _latestHighSignal;
private decimal _latestLowSignal;
private decimal _lastExecutedHigh;
private decimal _lastExecutedLow;
private DateTimeOffset? _lastSignalTime;
private decimal? _bestLongPrice;
private decimal? _bestShortPrice;
private decimal _trailingDistance;
public decimal TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
public decimal StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
public decimal TrailingStopPoints
{
get => _trailingStopPoints.Value;
set => _trailingStopPoints.Value = value;
}
public int ReversePoint
{
get => _reversePoint.Value;
set => _reversePoint.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public ERp250Strategy()
{
_takeProfitPoints = Param(nameof(TakeProfitPoints), 15m)
.SetDisplay("Take Profit Points", "Take profit distance in price points", "Risk")
;
_stopLossPoints = Param(nameof(StopLossPoints), 999m)
.SetDisplay("Stop Loss Points", "Stop loss distance in price points", "Risk")
;
_trailingStopPoints = Param(nameof(TrailingStopPoints), 0m)
.SetDisplay("Trailing Stop Points", "Trailing stop distance in price points", "Risk")
;
_reversePoint = Param(nameof(ReversePoint), 400)
.SetDisplay("Reverse Point Length", "Candles used to confirm reversal points", "Signals")
.SetGreaterThanZero()
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Type of candles to analyse", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_highest = null;
_lowest = null;
_latestHighSignal = 0m;
_latestLowSignal = 0m;
_lastExecutedHigh = 0m;
_lastExecutedLow = 0m;
_lastSignalTime = null;
_bestLongPrice = null;
_bestShortPrice = null;
_trailingDistance = 0m;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_highest = new Highest { Length = ReversePoint };
_lowest = new Lowest { Length = ReversePoint };
var step = Security?.PriceStep ?? 1m;
if (step <= 0m)
step = 1m;
var takeDistance = TakeProfitPoints > 0m ? step * TakeProfitPoints : 0m;
var stopDistance = StopLossPoints > 0m ? step * StopLossPoints : 0m;
_trailingDistance = TrailingStopPoints > 0m ? step * TrailingStopPoints : 0m;
// Enable protective orders that match the original stop and take-profit distances.
StartProtection(
takeDistance > 0m ? new Unit(takeDistance, UnitTypes.Absolute) : default,
stopDistance > 0m ? new Unit(stopDistance, UnitTypes.Absolute) : default
);
var subscription = SubscribeCandles(CandleType);
subscription.Bind(ProcessCandle).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
var highValue = _highest.Process(new DecimalIndicatorValue(_highest, candle.HighPrice, candle.OpenTime) { IsFinal = true }).ToNullableDecimal();
var lowValue = _lowest.Process(new DecimalIndicatorValue(_lowest, candle.LowPrice, candle.OpenTime) { IsFinal = true }).ToNullableDecimal();
if (highValue is null || lowValue is null)
return;
// Update the latest reversal levels detected by the rolling highest/lowest indicators.
if (highValue.Value == candle.HighPrice)
_latestHighSignal = candle.HighPrice;
if (lowValue.Value == candle.LowPrice)
_latestLowSignal = candle.LowPrice;
// Manage an existing long position by trailing profits and reacting to opposite signals.
if (Position > 0)
{
_bestLongPrice = (_bestLongPrice is null || candle.HighPrice > _bestLongPrice) ? candle.HighPrice : _bestLongPrice;
if (_trailingDistance > 0m && _bestLongPrice is decimal bestLong && bestLong - candle.ClosePrice >= _trailingDistance)
{
SellMarket();
_bestLongPrice = null;
return;
}
if (_latestHighSignal != 0m && _latestHighSignal != _lastExecutedHigh)
{
SellMarket();
_bestLongPrice = null;
return;
}
}
else if (Position < 0)
{
_bestShortPrice = (_bestShortPrice is null || candle.LowPrice < _bestShortPrice) ? candle.LowPrice : _bestShortPrice;
if (_trailingDistance > 0m && _bestShortPrice is decimal bestShort && candle.ClosePrice - bestShort >= _trailingDistance)
{
BuyMarket();
_bestShortPrice = null;
return;
}
if (_latestLowSignal != 0m && _latestLowSignal != _lastExecutedLow)
{
BuyMarket();
_bestShortPrice = null;
return;
}
}
else
{
_bestLongPrice = null;
_bestShortPrice = null;
}
if (Position != 0)
return;
// Avoid placing more than one order within the same candle.
if (_lastSignalTime == candle.OpenTime)
return;
// Execute a new short position when a fresh reversal high is detected.
if (_latestHighSignal != 0m && _latestHighSignal != _lastExecutedHigh)
{
SellMarket();
_lastExecutedHigh = _latestHighSignal;
_lastSignalTime = candle.OpenTime;
_bestShortPrice = candle.ClosePrice;
_bestLongPrice = null;
return;
}
// Execute a new long position when a fresh reversal low is detected.
if (_latestLowSignal != 0m && _latestLowSignal != _lastExecutedLow)
{
BuyMarket();
_lastExecutedLow = _latestLowSignal;
_lastSignalTime = candle.OpenTime;
_bestLongPrice = candle.ClosePrice;
_bestShortPrice = null;
}
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class e_rp250_strategy(Strategy):
def __init__(self):
super(e_rp250_strategy, self).__init__()
self._take_profit_points = self.Param("TakeProfitPoints", 15.0)
self._stop_loss_points = self.Param("StopLossPoints", 999.0)
self._trailing_stop_points = self.Param("TrailingStopPoints", 0.0)
self._reverse_point = self.Param("ReversePoint", 400)
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4)))
self._latest_high_signal = 0.0
self._latest_low_signal = 0.0
self._last_executed_high = 0.0
self._last_executed_low = 0.0
self._last_signal_time = None
self._best_long_price = None
self._best_short_price = None
self._trailing_distance = 0.0
@property
def TakeProfitPoints(self):
return self._take_profit_points.Value
@TakeProfitPoints.setter
def TakeProfitPoints(self, value):
self._take_profit_points.Value = value
@property
def StopLossPoints(self):
return self._stop_loss_points.Value
@StopLossPoints.setter
def StopLossPoints(self, value):
self._stop_loss_points.Value = value
@property
def TrailingStopPoints(self):
return self._trailing_stop_points.Value
@TrailingStopPoints.setter
def TrailingStopPoints(self, value):
self._trailing_stop_points.Value = value
@property
def ReversePoint(self):
return self._reverse_point.Value
@ReversePoint.setter
def ReversePoint(self, value):
self._reverse_point.Value = value
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
def OnStarted2(self, time):
super(e_rp250_strategy, self).OnStarted2(time)
self._highest = Highest()
self._highest.Length = self.ReversePoint
self._lowest = Lowest()
self._lowest.Length = self.ReversePoint
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if step <= 0.0:
step = 1.0
take_distance = step * float(self.TakeProfitPoints) if float(self.TakeProfitPoints) > 0.0 else 0.0
stop_distance = step * float(self.StopLossPoints) if float(self.StopLossPoints) > 0.0 else 0.0
self._trailing_distance = step * float(self.TrailingStopPoints) if float(self.TrailingStopPoints) > 0.0 else 0.0
tp_unit = Unit(take_distance, UnitTypes.Absolute) if take_distance > 0.0 else Unit()
sl_unit = Unit(stop_distance, UnitTypes.Absolute) if stop_distance > 0.0 else Unit()
self.StartProtection(tp_unit, sl_unit)
self._latest_high_signal = 0.0
self._latest_low_signal = 0.0
self._last_executed_high = 0.0
self._last_executed_low = 0.0
self._last_signal_time = None
self._best_long_price = None
self._best_short_price = None
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self.ProcessCandle).Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
high_result = process_float(self._highest, candle.HighPrice, candle.OpenTime, True)
low_result = process_float(self._lowest, candle.LowPrice, candle.OpenTime, True)
if high_result.IsEmpty or low_result.IsEmpty:
return
high_value = float(high_result)
low_value = float(low_result)
if abs(high_value - high) < 1e-10:
self._latest_high_signal = high
if abs(low_value - low) < 1e-10:
self._latest_low_signal = low
# Manage existing long position
if self.Position > 0:
if self._best_long_price is None or high > self._best_long_price:
self._best_long_price = high
if self._trailing_distance > 0.0 and self._best_long_price is not None and self._best_long_price - close >= self._trailing_distance:
self.SellMarket()
self._best_long_price = None
return
if self._latest_high_signal != 0.0 and self._latest_high_signal != self._last_executed_high:
self.SellMarket()
self._best_long_price = None
return
elif self.Position < 0:
if self._best_short_price is None or low < self._best_short_price:
self._best_short_price = low
if self._trailing_distance > 0.0 and self._best_short_price is not None and close - self._best_short_price >= self._trailing_distance:
self.BuyMarket()
self._best_short_price = None
return
if self._latest_low_signal != 0.0 and self._latest_low_signal != self._last_executed_low:
self.BuyMarket()
self._best_short_price = None
return
else:
self._best_long_price = None
self._best_short_price = None
if self.Position != 0:
return
# Avoid placing more than one order within the same candle
if self._last_signal_time is not None and self._last_signal_time == candle.OpenTime:
return
# Short on fresh reversal high
if self._latest_high_signal != 0.0 and self._latest_high_signal != self._last_executed_high:
self.SellMarket()
self._last_executed_high = self._latest_high_signal
self._last_signal_time = candle.OpenTime
self._best_short_price = close
self._best_long_price = None
return
# Long on fresh reversal low
if self._latest_low_signal != 0.0 and self._latest_low_signal != self._last_executed_low:
self.BuyMarket()
self._last_executed_low = self._latest_low_signal
self._last_signal_time = candle.OpenTime
self._best_long_price = close
self._best_short_price = None
def OnReseted(self):
super(e_rp250_strategy, self).OnReseted()
self._latest_high_signal = 0.0
self._latest_low_signal = 0.0
self._last_executed_high = 0.0
self._last_executed_low = 0.0
self._last_signal_time = None
self._best_long_price = None
self._best_short_price = None
self._trailing_distance = 0.0
def CreateClone(self):
return e_rp250_strategy()