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
Seleccionar la fuente de precio (close, open, variantes ponderadas, precios de seguimiento de tendencia, etc.).
Suavizar ese flujo de precios con una primera media móvil (PriceMaMethod, PriceMaLength).
Dividir la diferencia entre el precio y el valor suavizado en flujos positivos y negativos.
Suavizar los flujos positivos y negativos de forma independiente con una segunda media móvil (SmoothingMethod, SmoothingLength).
Calcular el Índice de Intensidad de Tendencia: TII = 100 * Positive / (Positive + Negative).
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();
}
}
}
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 ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_trend_intensity_index_strategy(Strategy):
def __init__(self):
super(exp_trend_intensity_index_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._fast_period = self.Param("FastPeriod", 10) \
.SetDisplay("Fast EMA", "Fast EMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow EMA", "Slow EMA period", "Indicators")
self._prev_fast = None
self._prev_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(exp_trend_intensity_index_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(exp_trend_intensity_index_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_slow is None:
self._prev_fast = fv
self._prev_slow = sv
return
prev_above = self._prev_fast > self._prev_slow
curr_above = fv > sv
self._prev_fast = fv
self._prev_slow = sv
if not prev_above and curr_above and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif prev_above and not curr_above and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return exp_trend_intensity_index_strategy()