Esta estratégia implementa o algoritmo Nick Rypock Trailing Reverse (NRTR) com setas de sinal adicionais. É uma conversão do exemplo original do MQL5 "Exp_NRTR_extr" para a API de alto nível do StockSharp.
Como funciona
O NrtrExtrIndicator personalizado calcula uma faixa média durante um período configurável e desenha um nível de trailing que segue o preço.
Quando o preço reverte além desse nível, o indicador muda de direção e emite um sinal de compra ou venda.
A estratégia abre uma posição comprada em um sinal de compra e uma posição vendida em um sinal de venda.
As posições existentes são fechadas no sinal oposto ou quando os níveis definidos de stop loss ou take profit são atingidos.
Parâmetros
Nome
Descrição
Period
Número de velas usadas para o cálculo da faixa média.
Digits Shift
Ajuste de precisão adicional aplicado ao fator de faixa.
Stop Loss
Stop de proteção em pontos de preço.
Take Profit
Alvo de lucro em pontos de preço.
Enable Buy Open / Enable Sell Open
Permitir abertura de posições compradas ou vendidas.
Enable Buy Close / Enable Sell Close
Permitir fechamento de posições existentes em sinais opostos.
Candle Type
Período de tempo das velas usadas para o indicador.
Notas
O indicador é baseado no Average True Range para estimar a volatilidade do mercado. Para visualização, a estratégia desenha automaticamente velas e operações executadas na área do gráfico.
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()