Auf GitHub ansehen

NRTR Revers-Strategie

Übersicht

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

  1. 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.
  2. 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.
  3. 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.
  4. 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.
  5. 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;
		}
	}
}