Auf GitHub ansehen

NRTR Extr-Strategie

Diese Strategie implementiert den Nick Rypock Trailing Reverse (NRTR)-Algorithmus mit zusätzlichen Signalpfeilen. Es handelt sich um eine Konvertierung des originalen MQL5-Beispiels „Exp_NRTR_extr" zur StockSharp High-Level-API.

Funktionsweise

  • Der benutzerdefinierte NrtrExtrIndicator berechnet eine durchschnittliche Spanne über einen konfigurierbaren Zeitraum und zeichnet ein Trailing-Level, das dem Preis folgt.
  • Wenn der Preis über dieses Level hinaus umkehrt, wechselt der Indikator die Richtung und sendet ein Kauf- oder Verkaufssignal.
  • Die Strategie eröffnet bei einem Kaufsignal eine Long-Position und bei einem Verkaufssignal eine Short-Position.
  • Bestehende Positionen werden bei entgegengesetztem Signal oder beim Erreichen der definierten Stop-Loss- oder Take-Profit-Levels geschlossen.

Parameter

Name Beschreibung
Period Anzahl der Kerzen für die Berechnung der durchschnittlichen Spanne.
Digits Shift Zusätzliche Präzisionsanpassung des Spannenfaktors.
Stop Loss Schutz-Stop in Preispunkten.
Take Profit Gewinnziel in Preispunkten.
Enable Buy Open / Enable Sell Open Öffnen von Long- oder Short-Positionen erlauben.
Enable Buy Close / Enable Sell Close Schließen bestehender Positionen bei entgegengesetzten Signalen erlauben.
Candle Type Zeitrahmen der für den Indikator verwendeten Kerzen.

Hinweise

Der Indikator basiert auf dem Average True Range zur Schätzung der Marktvolatilität. Zur Visualisierung zeichnet die Strategie automatisch Kerzen und ausgeführte Trades im Chartbereich.

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>
/// NRTR Extr strategy - trend following based on ATR-based trailing levels.
/// Opens long when trend turns up, short when trend turns down.
/// </summary>
public class NrtrExtrStrategy : Strategy
{
	private readonly StrategyParam<int> _period;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _price;
	private decimal _value;
	private int _trend;
	private int _trendPrev;
	private bool _initialized;

	public int Period { get => _period.Value; set => _period.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public NrtrExtrStrategy()
	{
		_period = Param(nameof(Period), 10)
			.SetGreaterThanZero()
			.SetDisplay("Period", "ATR period for NRTR", "Indicator")
			.SetOptimize(5, 20, 5);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Time frame", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnReseted()
	{
		base.OnReseted();
		_price = 0;
		_value = 0;
		_trend = 0;
		_trendPrev = 0;
		_initialized = false;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var atr = new AverageTrueRange { Length = Period };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue atrValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!atrValue.IsFormed)
			return;

		var atr = atrValue.GetValue<decimal>();

		if (atr <= 0)
			return;

		if (!_initialized)
		{
			_price = candle.ClosePrice;
			_value = candle.ClosePrice;
			_trend = 1;
			_trendPrev = 1;
			_initialized = true;
			return;
		}

		var dK = atr / Period;

		if (_trend >= 0)
		{
			_price = Math.Max(_price, candle.HighPrice);
			_value = Math.Max(_value, _price * (1m - dK));

			if (candle.ClosePrice < _value)
			{
				_price = candle.LowPrice;
				_value = _price * (1m + dK);
				_trend = -1;
			}
		}
		else
		{
			_price = Math.Min(_price, candle.LowPrice);
			_value = Math.Min(_value, _price * (1m + dK));

			if (candle.ClosePrice > _value)
			{
				_price = candle.HighPrice;
				_value = _price * (1m - dK);
				_trend = 1;
			}
		}

		var buySignal = _trendPrev <= 0 && _trend > 0;
		var sellSignal = _trendPrev >= 0 && _trend < 0;

		if (IsFormedAndOnlineAndAllowTrading())
		{
			if (buySignal && Position <= 0)
				BuyMarket();
			else if (sellSignal && Position >= 0)
				SellMarket();
		}

		_trendPrev = _trend;
	}
}