Ver no GitHub

Estratégia Exp Índice de Intensidade de Tendência

Esta estratégia é uma conversão StockSharp do especialista MetaTrader Exp_Trend_Intensity_Index. Ela opera em velas finalizadas em um período configurável e usa o Índice de Intensidade de Tendência (TII) para detectar quando o momentum sai de zonas altistas ou baixistas extremas. Quando o indicador faz a transição para fora de uma zona superior, o algoritmo fecha posições vendidas e pode iniciar uma nova posição comprada. Quando o indicador sai de uma zona inferior, o algoritmo fecha posições compradas e pode iniciar uma nova posição vendida.

Como o indicador é construído

  1. Selecionar a fonte de preço (close, open, variantes ponderadas, preços de acompanhamento de tendência, etc.).
  2. Suavizar esse fluxo de preços com uma primeira média móvel (PriceMaMethod, PriceMaLength).
  3. Dividir a diferença entre o preço e o valor suavizado em fluxos positivos e negativos.
  4. Suavizar os fluxos positivos e negativos independentemente com uma segunda média móvel (SmoothingMethod, SmoothingLength).
  5. Calcular o Índice de Intensidade de Tendência: TII = 100 * Positive / (Positive + Negative).
  6. Comparar o resultado com os limites HighLevel e LowLevel para atribuir um estado de cor: zona alta (0), neutro (1) ou zona baixa (2).

A implementação usa médias móveis do StockSharp (simples, exponencial, suavizada, ponderada). Tipos de suavização avançados da biblioteca MQL original não estão disponíveis neste port.

Lógica de trading

  • Os sinais são processados apenas quando uma vela está completamente fechada (CandleStates.Finished).
  • O parâmetro SignalBar define qual barra completada é analisada (padrão: uma barra atrás). A estratégia também inspeciona a barra imediatamente anterior, correspondendo à busca de buffer duplo no código MQL.
  • Quando a barra mais antiga pertence à zona alta (color == 0):
    • Fechar qualquer posição vendida se EnableSellExits for verdadeiro.
    • Se a barra mais recente saiu da zona alta e EnableBuyEntries for verdadeiro, abrir ou reverter para uma posição comprada.
  • Quando a barra mais antiga pertence à zona baixa (color == 2):
    • Fechar qualquer posição comprada se EnableBuyExits for verdadeiro.
    • Se a barra mais recente saiu da zona baixa e EnableSellEntries for verdadeiro, abrir ou reverter para uma posição vendida.
  • As ordens são enviadas com BuyMarket e SellMarket. As reversões de posição usam o volume de posição atual mais a propriedade Volume configurada.
  • A proteção opcional de stop-loss e take-profit (unidades de preço) é configurada através de StopLossPoints e TakeProfitPoints e implementada com StartProtection.

Parâmetros

Parâmetro Descrição
CandleType Período usado para cálculo do indicador e negociação.
PriceMaMethod, PriceMaLength Tipo e período da média móvel aplicada ao fluxo de preço base.
SmoothingMethod, SmoothingLength Tipo e período da média móvel aplicada aos fluxos positivos e negativos.
AppliedPrice Fonte de preço para o indicador (close, open, median, variantes de acompanhamento de tendência, Demark, etc.).
HighLevel, LowLevel Limites superiores e inferiores que definem zonas altistas e baixistas.
SignalBar Número de barras completadas para olhar para trás para confirmação de sinal.
EnableBuyEntries, EnableSellEntries Interruptores que permitem abrir posições compradas/vendidas.
EnableBuyExits, EnableSellExits Interruptores que permitem saídas automáticas quando o indicador muda.
StopLossPoints, TakeProfitPoints Distâncias protetoras opcionais expressas em unidades de preço para StartProtection.

Diferenças do especialista MQL original

  • As opções de gestão monetária (MM, MMMode, Deviation) são substituídas pela propriedade de volume padrão do StockSharp e execução de ordens; o gerenciamento de slippage não é replicado.
  • Apenas os tipos de média móvel disponíveis no StockSharp (simples, exponencial, suavizada, ponderada) são suportados.
  • Os parâmetros de fase do indicador MQL são omitidos porque os indicadores do StockSharp não expõem controles equivalentes.
  • As ordens são executadas imediatamente após a confirmação de um sinal na vela finalizada; não há agendamento explícito para a próxima abertura de barra.

Essas mudanças mantêm a ideia de negociação intacta enquanto seguem as diretrizes de estratégia de alto nível do StockSharp.

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>
/// Trend Intensity Index strategy. Uses EMA crossover for trend following.
/// </summary>
public class ExpTrendIntensityIndexStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevFast;
	private decimal? _prevSlow;

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

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public ExpTrendIntensityIndexStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 30)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = null;
		_prevSlow = null;

		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };

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

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

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal slowVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		if (_prevFast == null || _prevSlow == null)
		{
			_prevFast = fastVal;
			_prevSlow = slowVal;
			return;
		}

		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fastVal > slowVal;

		_prevFast = fastVal;
		_prevSlow = slowVal;

		if (!prevAbove && currAbove && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (prevAbove && !currAbove && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}