Ver no GitHub

2526 Estratégia TDI-2 ReOpen

Visão geral

Esta estratégia é uma conversão em C# do consultor especialista do MetaTrader 5 Exp_TDI-2_ReOpen. Opera usando o indicador Trend Direction Index (TDI-2) e aplica a lógica original de re-entrada em posições. O port em C# usa a API de alto nível do StockSharp e mantém o comportamento central da versão MQL: reage a cruzamentos entre a linha de momentum TDI e a linha de índice TDI, escala em posições lucrativas após um avanço de preço configurável, e gerencia trades com stops protetores opcionais.

Indicadores

  • Indicador TDI-2 – um indicador personalizado baseado em momentum implementado neste repositório. Constrói duas linhas:
    • Linha direcional: Período × MomentumSuavizado, onde o momentum é igual ao preço aplicado menos o preço Período barras atrás.
    • Linha de índice: |Direcional| − (2 × Período × Suavizado(|Momentum|, 2×Período) − |Momentum|).
  • O indicador suporta os seguintes métodos de suavização: média móvel Simples, Exponencial, Suavizada (RMA) e Linearmente Ponderada.
  • As opções de preço aplicado suportadas replicam a implementação MQL original, incluindo as fórmulas TrendFollow e Demark.

Lógica de trading

  1. Em cada vela finalizada, a estratégia avalia os valores TDI-2 na barra especificada por Signal Bar (padrão: vela anterior fechada) e uma barra antes.
  2. Quando a linha direcional estava acima da linha de índice e depois cruza abaixo:
    • Se Allow Long Entries estiver habilitado e não houver posição comprada ativa, a estratégia prepara uma nova entrada comprada.
    • Se existir uma posição vendida e Allow Short Exits estiver habilitado, fecha a posição vendida.
  3. Quando a linha direcional estava abaixo da linha de índice e depois cruza acima:
    • Se Allow Short Entries estiver habilitado e não houver posição vendida ativa, a estratégia prepara uma nova entrada vendida.
    • Se existir uma posição comprada e Allow Long Exits estiver habilitado, fecha a posição comprada.
  4. Lógica de re-entrada (escalonamento):
    • Enquanto mantém uma posição comprada, a estratégia rastreia o preço de execução do último trade comprado. Se o mercado se mover favoravelmente em Re-entry Step (points) e o número de trades comprados executados ainda estiver abaixo de Max Entries, abre uma ordem comprada adicional com o volume base.
    • A mesma lógica aplica-se a posições vendidas usando o preço de execução vendido mais recente.
  5. Ao abrir uma posição enquanto existe uma posição contrária, a estratégia envia uma ordem a mercado combinada dimensionada tanto para fechar a exposição contrária quanto para estabelecer a nova posição com o volume base configurado.
  6. Os níveis opcionais de stop-loss e take-profit são ativados através de StartProtection usando o multiplicador PriceStep do instrumento.

Parâmetros

Nome Descrição Valores padrão
Money Management Volume de ordem base. 0.1
Max Entries Número máximo de entradas por direção (trade inicial + re-entradas). 10
Stop Loss (points) Distância do stop-loss em pontos do instrumento. 1000
Take Profit (points) Distância do take-profit em pontos do instrumento. 2000
Slippage (points) Mantido por compatibilidade; não usado na implementação do StockSharp. 10
Re-entry Step (points) Movimento mínimo favorável antes de escalar em uma posição existente. 300
Allow Long Entries / Allow Short Entries Habilitar abertura de posições compradas/vendidas. true
Allow Long Exits / Allow Short Exits Habilitar fechamento de posições compradas/vendidas. true
Candle Type Série de velas usada para os cálculos. Velas H4
TDI Smoothing Método de suavização para o indicador TDI-2. MA Simples
TDI Period Período de lookback do momentum. 20
TDI Phase Reservado para compatibilidade com o input MQL (sem efeito nos modos de suavização suportados). 15
Applied Price Fonte de preço usada pelo TDI-2. Close
Signal Bar Número de velas fechadas a olhar para trás ao avaliar cruzamentos. 1

Notas adicionais

  • Apenas os métodos de suavização suportados pelos indicadores do StockSharp (SMA, EMA, SMMA, LWMA) são implementados. Outros modos MQL como JJMA ou T3 não estão disponíveis.
  • O parâmetro TDI Phase é mantido por completude. Não influencia os métodos de suavização suportados e pode ser deixado no seu valor padrão.
  • O parâmetro Slippage (points) é fornecido por paridade com o consultor especialista original, mas não é usado pela API de alto nível.
  • Os contadores de re-entrada são reiniciados automaticamente quando a posição líquida retorna a zero.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trend Direction Index re-entry strategy.
/// Trades based on crossings between the TDI momentum line and the TDI index line.
/// </summary>
public class Tdi2ReOpenStrategy : Strategy
{
	private readonly StrategyParam<int> _tdiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal? _lastClose;
	private decimal? _directional;
	private decimal? _index;
	private decimal? _prevDirectional;
	private decimal? _prevIndex;

	public int TdiPeriod { get => _tdiPeriod.Value; set => _tdiPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public Tdi2ReOpenStrategy()
	{
		_tdiPeriod = Param(nameof(TdiPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("TDI Period", "Momentum lookback period", "Indicator")
			.SetOptimize(5, 30, 5);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Data series", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_lastClose = null;
		_directional = null;
		_index = null;
		_prevDirectional = null;
		_prevIndex = null;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_lastClose = null;
		_directional = null;
		_index = null;
		_prevDirectional = null;
		_prevIndex = null;

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ProcessCandle).Start();

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

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

			var close = candle.ClosePrice;
			if (_lastClose is not decimal lastClose)
			{
				_lastClose = close;
				return;
			}

			var momentum = close - lastClose;
			_lastClose = close;
			var alpha = 2m / (TdiPeriod + 1m);

			if (_directional is not decimal prevDirectionalLine || _index is not decimal prevIndexLine)
			{
				_directional = momentum;
				_index = momentum;
				return;
			}

			var directional = prevDirectionalLine + alpha * (momentum - prevDirectionalLine);
			var index = prevIndexLine + alpha * (directional - prevIndexLine);

			if (_prevDirectional is not decimal prevDir || _prevIndex is not decimal prevIdx)
			{
				_directional = directional;
				_index = index;
				_prevDirectional = prevDirectionalLine;
				_prevIndex = prevIndexLine;
				return;
			}

			var crossUp = prevDir <= prevIdx && directional > index;
			var crossDown = prevDir >= prevIdx && directional < index;

			if (crossUp && Position <= 0)
				BuyMarket();
			else if (crossDown && Position >= 0)
				SellMarket();

			_directional = directional;
			_index = index;
			_prevDirectional = directional;
			_prevIndex = index;
		}
	}
}