Ver en GitHub

Estrategia Exp Índice de Intensidad de Tendencia

Esta estrategia es una conversión de StockSharp del experto de MetaTrader Exp_Trend_Intensity_Index. Opera velas finalizadas en un marco temporal configurable y utiliza el Índice de Intensidad de Tendencia (TII) para detectar cuando el momentum sale de zonas alcistas o bajistas extremas. Cuando el indicador hace la transición fuera de una zona superior, el algoritmo cierra cortos y puede iniciar un nuevo largo. Cuando el indicador sale de una zona inferior, el algoritmo cierra largos y puede iniciar un nuevo corto.

Cómo se construye el indicador

  1. Seleccionar la fuente de precio (close, open, variantes ponderadas, precios de seguimiento de tendencia, etc.).
  2. Suavizar ese flujo de precios con una primera media móvil (PriceMaMethod, PriceMaLength).
  3. Dividir la diferencia entre el precio y el valor suavizado en flujos positivos y negativos.
  4. Suavizar los flujos positivos y negativos de forma independiente con una segunda media móvil (SmoothingMethod, SmoothingLength).
  5. Calcular el Índice de Intensidad de Tendencia: TII = 100 * Positive / (Positive + Negative).
  6. Comparar el resultado con los umbrales HighLevel y LowLevel para asignar un estado de color: zona alta (0), neutral (1) o zona baja (2).

La implementación usa medias móviles de StockSharp (simple, exponencial, suavizada, ponderada). Los tipos de suavizado avanzado de la biblioteca MQL original no están disponibles en este port.

Lógica de trading

  • Las señales se procesan solo cuando una vela está completamente cerrada (CandleStates.Finished).
  • El parámetro SignalBar define qué barra completada se analiza (por defecto un barra hacia atrás). La estrategia también inspecciona la barra inmediatamente anterior, coincidiendo con la búsqueda de doble búfer en el código MQL.
  • Cuando la barra más antigua pertenece a la zona alta (color == 0):
    • Cerrar cualquier posición corta si EnableSellExits es verdadero.
    • Si la barra más reciente salió de la zona alta y EnableBuyEntries es verdadero, abrir o revertir a una posición larga.
  • Cuando la barra más antigua pertenece a la zona baja (color == 2):
    • Cerrar cualquier posición larga si EnableBuyExits es verdadero.
    • Si la barra más reciente salió de la zona baja y EnableSellEntries es verdadero, abrir o revertir a una posición corta.
  • Las órdenes se envían con BuyMarket y SellMarket. Las reversiones de posición usan el volumen de posición actual más la propiedad Volume configurada.
  • La protección opcional de stop-loss y take-profit (unidades de precio) se configura a través de StopLossPoints y TakeProfitPoints y se implementa con StartProtection.

Parámetros

Parámetro Descripción
CandleType Marco temporal usado para el cálculo del indicador y el trading.
PriceMaMethod, PriceMaLength Tipo y periodo de la media móvil aplicada al flujo de precio base.
SmoothingMethod, SmoothingLength Tipo y periodo de la media móvil aplicada a los flujos positivos y negativos.
AppliedPrice Fuente de precio para el indicador (close, open, median, variantes de seguimiento de tendencia, Demark, etc.).
HighLevel, LowLevel Umbrales superiores e inferiores que definen las zonas alcista y bajista.
SignalBar Número de barras completadas a mirar hacia atrás para confirmación de señal.
EnableBuyEntries, EnableSellEntries Interruptores que permiten abrir posiciones largas/cortas.
EnableBuyExits, EnableSellExits Interruptores que permiten salidas automáticas cuando el indicador cambia.
StopLossPoints, TakeProfitPoints Distancias protectoras opcionales expresadas en unidades de precio para StartProtection.

Diferencias con el experto MQL original

  • Las opciones de gestión del dinero (MM, MMMode, Deviation) se reemplazan con la propiedad de volumen estándar de StockSharp y la ejecución de órdenes; la gestión de deslizamiento no se replica.
  • Solo se admiten los tipos de media móvil disponibles en StockSharp (simple, exponencial, suavizada, ponderada).
  • Los parámetros de fase del indicador MQL se omiten porque los indicadores de StockSharp no exponen controles equivalentes.
  • Las órdenes se ejecutan inmediatamente después de que se confirma una señal en la vela finalizada; no hay programación explícita para la siguiente apertura de barra.

Estos cambios mantienen la idea de trading intacta mientras siguen las directrices de estrategia de alto nivel de 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();
		}
	}
}