Die NRTR Revers-Strategie ist eine C#-Konvertierung des originalen MetaTrader 5 Expert Advisors NRTR_Revers.mq5. Das System verwendet den Nick Rypock Trailing Reverse (NRTR)-Ansatz, um je nach Preisinteraktion mit ATR-projizierten Unterstützungs- und Widerstandsbändern zwischen Long- und Short-Bias zu wechseln. Handelsentscheidungen werden beim Schlusskurs jeder abgeschlossenen Kerze einer Single-Timeframe-Subscription bewertet.
Handelslogik
ATR-Projektion – Die Strategie berechnet einen Average True Range (ATR) mit der konfigurierbaren Periode. Der ATR-Wert wird mit dem VolatilityMultiplier multipliziert, um den Bandversatz zu erhalten.
Dynamische Bänder – Für die aktuelle Trendrichtung findet die Strategie:
Das niedrigste Tief (oder höchste Hoch) unter den Kerzen, die mit der ursprünglichen MQL-Fensterkonfiguration übereinstimmen.
Ein sekundäres Extrem, das tiefer in die Geschichte verschoben ist. Der Abstand zwischen dem primären Band und diesem sekundären Extrem wird zusammen mit dem ReversePips-Schwellenwert verwendet, um starke Umkehrungen zu bestätigen.
Trendwechsel – Wenn der vorherige Schlusskurs sich außerhalb des ATR-Bandes bewegt oder die sekundäre Extremdifferenz die Umkehrdistanz überschreitet, wechselt der Bias (von Long zu Short oder umgekehrt). Wenn eine entgegengesetzte Position existiert, wird sie zuerst geschlossen; andernfalls wird sofort eine neue Position in der neuen Richtung eröffnet.
Warten auf flache Position – Nach dem Ausgeben einer entgegengesetzten Market-Order zum Schließen einer bestehenden Position wartet die Strategie, bis das Portfolio flach ist, bevor sie die neue Entry-Order einreicht. Dieses Verhalten spiegelt den ursprünglichen Expert Advisor wider.
Risikomanagement – Stop-Loss-, Take-Profit- und Trailing-Stop-Levels werden in Pips definiert und mithilfe eines angepassten Punktwerts (kompatibel mit 3- und 5-stelligen Forex-Symbolen) in absolute Preise umgerechnet. Trailing-Updates erfordern einen Preisfortschritt größer als TrailingStopPips + TrailingStepPips, entsprechend der MT5-Logik.
Parameter
CandleType – Primärer Zeitrahmen für die Subscription von Preisdaten.
AtrPeriod – ATR-Glättungslänge für die Bandberechnung.
VolatilityMultiplier – Auf den ATR-Wert angewendeter Multiplikator zur Dimensionierung des Versatzes vom Extrem.
ReversePips – Zusätzliche pip-basierte Distanz, die das sekundäre Extrem überschreiten muss, bevor der Bias kippt.
StopLossPips – Schützende Stop-Distanz in Pips vom Eintrittspreis (auf null setzen zum Deaktivieren).
TakeProfitPips – Gewinnziel-Distanz in Pips vom Eintrittspreis (auf null setzen zum Deaktivieren).
TrailingStopPips – Trailing-Stop-Aktivierungsdistanz in Pips (auf null setzen zum Deaktivieren des Trailings).
TrailingStepPips – Zusätzliche Pip-Distanz, die erforderlich ist, bevor Trailing-Updates auftreten; muss positiv sein, wenn Trailing aktiv ist.
TradeVolume – Ordervolumen für neue Einstiege (in Lots/Kontrakten je nach Wertpapiereinstellungen).
Hinweise
Die Indikatorberechnungen und Umkehrprüfungen verwenden nur abgeschlossene Kerzen; unvollständige Kerzen werden ignoriert.
Der vom Binding gelieferte ATR-Wert entspricht dem ATR der vorherigen Kerze, der im Quell-EA verwendet wird, da Berechnungen nach der Kerzenfertigstellung erfolgen.
Die angepasste Punktberechnung verarbeitet automatisch 3- und 5-stellige Forex-Kurse, um pip-basierte Parameter mit dem ursprünglichen Skript kompatibel zu halten.
Kein Python-Port ist auf Anfrage vorgesehen. Der Ordner enthält derzeit nur die C#-Implementierung und Dokumentation.
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>
/// NRTR reversal strategy using ATR channel around EMA.
/// Goes long when price breaks above EMA + ATR*multiplier.
/// Goes short when price breaks below EMA - ATR*multiplier.
/// </summary>
public class NrtrReversStrategy : Strategy
{
private readonly StrategyParam<int> _atrPeriod;
private readonly StrategyParam<decimal> _volatilityMultiplier;
private readonly StrategyParam<int> _emaPeriod;
private AverageTrueRange _atr;
private ExponentialMovingAverage _ema;
private decimal _entryPrice;
private int _cooldown;
/// <summary>
/// ATR period.
/// </summary>
public int AtrPeriod
{
get => _atrPeriod.Value;
set => _atrPeriod.Value = value;
}
/// <summary>
/// ATR multiplier for band calculation.
/// </summary>
public decimal VolatilityMultiplier
{
get => _volatilityMultiplier.Value;
set => _volatilityMultiplier.Value = value;
}
/// <summary>
/// EMA period for trend center.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// Initializes strategy parameters.
/// </summary>
public NrtrReversStrategy()
{
_atrPeriod = Param(nameof(AtrPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("ATR Period", "ATR averaging period", "Indicator");
_volatilityMultiplier = Param(nameof(VolatilityMultiplier), 5m)
.SetGreaterThanZero()
.SetDisplay("Multiplier", "ATR multiplier for bands", "Indicator");
_emaPeriod = Param(nameof(EmaPeriod), 100)
.SetGreaterThanZero()
.SetDisplay("EMA Period", "EMA trend center period", "Indicator");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_atr = null;
_ema = null;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_atr = new AverageTrueRange { Length = AtrPeriod };
_ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_atr, _ema, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal atrValue, decimal emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!_atr.IsFormed || !_ema.IsFormed)
return;
if (_cooldown > 0)
{
_cooldown--;
return;
}
var close = candle.ClosePrice;
var bandOffset = atrValue * VolatilityMultiplier;
var upperBand = emaValue + bandOffset;
var lowerBand = emaValue - bandOffset;
// Buy: price breaks above upper band
if (close > upperBand && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 50;
}
// Sell: price breaks below lower band
else if (close < lowerBand && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 50;
}
// Exit long: price returns to EMA
else if (Position > 0 && close < emaValue)
{
SellMarket();
_entryPrice = 0;
_cooldown = 50;
}
// Exit short: price returns to EMA
else if (Position < 0 && close > emaValue)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 50;
}
}
}
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 AverageTrueRange, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class nrtr_revers_strategy(Strategy):
def __init__(self):
super(nrtr_revers_strategy, self).__init__()
self._atr_period = self.Param("AtrPeriod", 14).SetGreaterThanZero().SetDisplay("ATR Period", "ATR averaging period", "Indicator")
self._volatility_multiplier = self.Param("VolatilityMultiplier", 5.0).SetGreaterThanZero().SetDisplay("Multiplier", "ATR multiplier for bands", "Indicator")
self._ema_period = self.Param("EmaPeriod", 100).SetGreaterThanZero().SetDisplay("EMA Period", "EMA trend center period", "Indicator")
@property
def CandleType(self):
return tf(5)
def OnReseted(self):
super(nrtr_revers_strategy, self).OnReseted()
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(nrtr_revers_strategy, self).OnStarted2(time)
self._entry_price = 0
self._cooldown = 0
self._atr = AverageTrueRange()
self._atr.Length = self._atr_period.Value
self._ema = ExponentialMovingAverage()
self._ema.Length = self._ema_period.Value
sub = self.SubscribeCandles(tf(5))
sub.Bind(self._atr, self._ema, self.OnProcess).Start()
def OnProcess(self, candle, atr_val, ema_val):
if candle.State != CandleStates.Finished:
return
if not self._atr.IsFormed or not self._ema.IsFormed:
return
if self._cooldown > 0:
self._cooldown -= 1
return
close = candle.ClosePrice
band_offset = atr_val * self._volatility_multiplier.Value
upper_band = ema_val + band_offset
lower_band = ema_val - band_offset
if close > upper_band and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 50
elif close < lower_band and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 50
elif self.Position > 0 and close < ema_val:
self.SellMarket()
self._entry_price = 0
self._cooldown = 50
elif self.Position < 0 and close > ema_val:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 50
def CreateClone(self):
return nrtr_revers_strategy()