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;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class nrtr_extr_strategy(Strategy):
def __init__(self):
super(nrtr_extr_strategy, self).__init__()
self._period = self.Param("Period", 10) \
.SetDisplay("Period", "ATR period for NRTR", "Indicator")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Time frame", "General")
self._price = 0.0
self._value = 0.0
self._trend = 0
self._trend_prev = 0
self._initialized = False
@property
def period(self):
return self._period.Value
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(nrtr_extr_strategy, self).OnReseted()
self._price = 0.0
self._value = 0.0
self._trend = 0
self._trend_prev = 0
self._initialized = False
def OnStarted2(self, time):
super(nrtr_extr_strategy, self).OnStarted2(time)
atr = AverageTrueRange()
atr.Length = self.period
subscription = self.SubscribeCandles(self.candle_type)
subscription.BindEx(atr, self.process_candle).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def process_candle(self, candle, atr_value):
if candle.State != CandleStates.Finished:
return
if not atr_value.IsFormed:
return
atr = float(atr_value)
if atr <= 0:
return
close = float(candle.ClosePrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
if not self._initialized:
self._price = close
self._value = close
self._trend = 1
self._trend_prev = 1
self._initialized = True
return
dk = atr / self.period
if self._trend >= 0:
self._price = max(self._price, high)
self._value = max(self._value, self._price * (1.0 - dk))
if close < self._value:
self._price = low
self._value = self._price * (1.0 + dk)
self._trend = -1
else:
self._price = min(self._price, low)
self._value = min(self._value, self._price * (1.0 + dk))
if close > self._value:
self._price = high
self._value = self._price * (1.0 - dk)
self._trend = 1
buy_signal = self._trend_prev <= 0 and self._trend > 0
sell_signal = self._trend_prev >= 0 and self._trend < 0
if buy_signal and self.Position <= 0:
self.BuyMarket()
elif sell_signal and self.Position >= 0:
self.SellMarket()
self._trend_prev = self._trend
def CreateClone(self):
return nrtr_extr_strategy()