Estratégia Exp Rj SlidingRangeRj Digit System Tm Plus
Visão geral
Esta estratégia StockSharp é um port do consultor especialista MetaTrader Exp_Rj_SlidingRangeRj_Digit_System_Tm_Plus. Ela recria a lógica de trading original baseada no indicador de canal personalizado Rj_SlidingRangeRj_Digit e preserva as opções configuráveis de gerenciamento de operações. A estratégia monitora candles finalizados em um período configurável, detecta rompimentos além do canal e reage a esses eventos com entradas atrasadas, saídas temporizadas opcionais e gerenciamento de stop/alvo baseado em preço.
Lógica do indicador
O indicador Rj_SlidingRangeRj_Digit constrói um canal de preço adaptativo usando um processo de média de múltiplas etapas:
Para a banda superior, o máximo-máximo dentro de UpCalcPeriodRange barras é calculado para cada uma das últimas UpCalcPeriodRange janelas deslizantes, deslocadas por UpCalcPeriodShift barras. A média dessas máximas é arredondada para a precisão especificada por UpDigit.
A banda inferior repete a mesma lógica para mínimas usando DnCalcPeriodRange, DnCalcPeriodShift e DnDigit.
Um candle é rotulado como rompimento quando seu preço de fechamento está acima da banda superior (cores 2 / 3) ou abaixo da banda inferior (cores 0 / 1). Candles dentro do canal produzem uma cor neutra (4).
A estratégia transmite candles finalizados, reconstrói as bandas em cada atualização e armazena os códigos de cor mais recentes para imitar o comportamento CopyBuffer/SignalBar da implementação MQL.
Regras de trading
Atraso de entrada: Os sinais são avaliados na barra definida por SignalBar (padrão uma barra atrás). A estratégia aguarda até que uma cor de rompimento apareça e a barra anterior não tenha a mesma cor de rompimento. Isso reproduz o atraso original de uma barra antes de tomar uma operação.
Entradas compradas: Habilitadas por EnableBuyEntries. Um rompimento altista (cor 2 ou 3) aciona uma compra de mercado quando não há posição comprada aberta (a exposição vendida é compensada automaticamente).
Entradas vendidas: Habilitadas por EnableSellEntries. Um rompimento baixista (cor 0 ou 1) aciona uma venda de mercado quando não há posição vendida aberta.
Sinais de saída:
Comprados fecham com cores de rompimento baixista se EnableBuyExits for verdadeiro.
Vendidos fecham com cores de rompimento altista se EnableSellExits for verdadeiro.
A saída opcional baseada em tempo (UseTimeExit) fecha qualquer posição aberta uma vez que tenha sido mantida por mais de ExitMinutes.
Níveis opcionais de stop-loss e take-profit expressos em pontos (StopLossPoints, TakeProfitPoints) são convertidos em deslocamentos de preço usando o PriceStep do instrumento.
Todas as ações usam BuyMarket / SellMarket para que a estratégia reverta automaticamente as posições quando necessário.
Parâmetros
Parâmetro
Descrição
Valor padrão
CandleType
Tipo de candle (período) usado para detecção de sinais.
Candles de 8 horas
EnableBuyEntries / EnableSellEntries
Permitir entradas de rompimento compradas/vendidas.
true
EnableBuyExits / EnableSellExits
Permitir saídas baseadas em indicador para comprados/vendidos.
true
UseTimeExit
Fechar operações após um tempo de manutenção fixo.
true
ExitMinutes
Limite de tempo de manutenção em minutos.
1920
UpCalcPeriodRange, UpCalcPeriodShift, UpDigit
Parâmetros da banda do canal superior.
5, 0, 2
DnCalcPeriodRange, DnCalcPeriodShift, DnDigit
Parâmetros da banda do canal inferior.
5, 0, 2
SignalBar
Deslocamento de barra usado para avaliar sinais de rompimento.
1
StopLossPoints, TakeProfitPoints
Stop-loss / take-profit em pontos de preço (convertidos com PriceStep).
1000, 2000
Defina a propriedade Volume da estratégia para controlar o dimensionamento de posição. Os parâmetros de stop-loss e take-profit são opcionais; defina-os como 0 para desabilitar qualquer nível de proteção.
Notas
A estratégia espera histórico suficiente para formar o canal deslizante (aproximadamente max(shift + 2 × range) candles). Gerencia automaticamente os buffers internos e ignora sinais até que dados suficientes estejam disponíveis.
O arredondamento de preço é realizado usando dígitos decimais, refletindo o comportamento de arredondamento do indicador MQL.
A implementação Python é omitida intencionalmente conforme as instruções do projeto; apenas a versão C# é fornecida.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Sliding range breakout strategy using Highest/Lowest channel.
/// Enters on breakout above/below the channel, exits on opposite breakout.
/// </summary>
public class ExpRjSlidingRangeRjDigitSystemTmPlusStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevUpper;
private decimal? _prevLower;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int Period
{
get => _period.Value;
set => _period.Value = value;
}
public ExpRjSlidingRangeRjDigitSystemTmPlusStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 10)
.SetGreaterThanZero()
.SetDisplay("Period", "Channel lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevUpper = null;
_prevLower = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevUpper = null;
_prevLower = null;
var highest = new Highest { Length = Period };
var lowest = new Lowest { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(highest, lowest, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, highest);
DrawIndicator(area, lowest);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal upper, decimal lower)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevUpper = upper;
_prevLower = lower;
return;
}
var close = candle.ClosePrice;
if (_prevUpper == null || _prevLower == null)
{
_prevUpper = upper;
_prevLower = lower;
return;
}
// Breakout above previous upper → buy
if (close > _prevUpper.Value && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Breakdown below previous lower → sell
else if (close < _prevLower.Value && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevUpper = upper;
_prevLower = lower;
}
}
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 Highest, Lowest
from StockSharp.Algo.Strategies import Strategy
class exp_rj_sliding_range_rj_digit_system_tm_plus_strategy(Strategy):
def __init__(self):
super(exp_rj_sliding_range_rj_digit_system_tm_plus_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 10) \
.SetDisplay("Period", "Channel lookback", "Indicators")
self._prev_upper = None
self._prev_lower = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(exp_rj_sliding_range_rj_digit_system_tm_plus_strategy, self).OnReseted()
self._prev_upper = None
self._prev_lower = None
def OnStarted2(self, time):
super(exp_rj_sliding_range_rj_digit_system_tm_plus_strategy, self).OnStarted2(time)
self._prev_upper = None
self._prev_lower = None
highest = Highest()
highest.Length = self.Period
lowest = Lowest()
lowest.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(highest, lowest, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, highest)
self.DrawIndicator(area, lowest)
self.DrawOwnTrades(area)
def _on_process(self, candle, upper_value, lower_value):
if candle.State != CandleStates.Finished:
return
uv = float(upper_value)
lv = float(lower_value)
close = float(candle.ClosePrice)
if self._prev_upper is None or self._prev_lower is None:
self._prev_upper = uv
self._prev_lower = lv
return
# Breakout above previous upper
if close > self._prev_upper and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Breakdown below previous lower
elif close < self._prev_lower and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_upper = uv
self._prev_lower = lv
def CreateClone(self):
return exp_rj_sliding_range_rj_digit_system_tm_plus_strategy()