GitHub で見る

NRTR Extr戦略

この戦略は追加シグナル矢印付きの Nick Rypock Trailing Reverse (NRTR) アルゴリズムを実装します。MQL5のオリジナル例「Exp_NRTR_extr」をStockSharp高レベルAPIに変換したものです。

動作方法

  • カスタムの NrtrExtrIndicator は設定可能な期間にわたる平均レンジを計算し、価格に追従するトレーリングレベルを描画します。
  • 価格がこのレベルを超えて反転すると、インジケーターは方向を変えて買いまたは売りシグナルを発します。
  • 戦略は買いシグナルでロングポジションを、売りシグナルでショートポジションを建てます。
  • 既存のポジションは反対シグナルで、または定義されたストップロスやテイクプロフィットレベルに達したときにクローズされます。

パラメーター

名前 説明
Period 平均レンジ計算に使用するローソク足の数。
Digits Shift レンジファクターに適用する追加精度調整。
Stop Loss 価格ポイント単位の保護ストップ。
Take Profit 価格ポイント単位の利益目標。
Enable Buy Open / Enable Sell Open ロングまたはショートポジションの建玉を許可。
Enable Buy Close / Enable Sell Close 反対シグナルでの既存ポジションのクローズを許可。
Candle Type インジケーターに使用するローソク足の時間軸。

注意事項

インジケーターは市場のボラティリティを推定するためにAverage True Rangeに基づいています。可視化のため、戦略はチャートエリアにローソク足と実行された取引を自動的に描画します。

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;
	}
}