Estrategia AbsolutelyNoLagLWMA Canal de Rango TM Plus
Descripción general
Esta estrategia es un port directo del experto MetaTrader "Exp_AbsolutelyNoLagLwma_Range_Channel_Tm_Plus". Opera un canal de precios derivado de una media móvil ponderada linealmente (LWMA) de doble suavizado de los máximos y mínimos de las velas. La versión StockSharp mantiene el comportamiento original: las señales se evalúan en velas finalizadas de un marco temporal seleccionable, el estado del canal se codifica de la misma manera que el indicador MQL, y la gestión de posiciones sigue el mismo orden de prioridad (salida por tiempo primero, salidas por indicador segundo, nuevas entradas al final).
Construcción del indicador
Para cada vela finalizada, las series de máximos y mínimos se introducen en una primera LWMA. El parámetro de longitud se comparte entre los flujos de máximos y mínimos.
La salida de la primera LWMA se suaviza nuevamente con otra LWMA de la misma longitud. Esto recrea el suavizado "AbsolutelyNoLagLWMA" utilizado por el indicador original.
Los valores finales del canal superior e inferior se comparan con el cierre de la vela:
Cierre por encima de la línea superior → estado de ruptura alcista.
Cierre por debajo de la línea inferior → estado de ruptura bajista.
Cierre dentro del canal → estado neutral.
La estrategia almacena los estados de canal más recientes. El parámetro SignalBar controla qué índice de barra se comprueba para la generación de señales (0 = última vela cerrada, 1 = una barra atrás, etc.), coincidiendo con la entrada SignalBar del programa MQL.
Interpretación de señales
Entrada larga – habilitada por EnableBuyEntries. La estrategia busca una ruptura alcista en la barra indexada por SignalBar + 1 mientras la barra en SignalBar ya ha retornado dentro del canal. El comportamiento replica la prueba original de "ruptura en barra anterior".
Entrada corta – habilitada por EnableSellEntries. Refleja la lógica larga para rupturas bajistas.
Salida larga – habilitada por EnableBuyExits. Una ruptura bajista en la barra de referencia cierra posiciones largas existentes, a menos que ya hayan sido cerradas por la salida basada en tiempo en la vela actual.
Salida corta – habilitada por EnableSellExits. Una ruptura alcista en la barra de referencia cierra posiciones cortas abiertas, a menos que la salida basada en tiempo ya haya solicitado el cierre.
Gestión de operaciones
Volumen de orden – tomado del parámetro OrderVolume. Las órdenes de reversión añaden automáticamente el valor absoluto de la posición actual para evitar exposición residual.
Stop loss / Take profit – compensaciones absolutas opcionales definidas en puntos del instrumento (StopLossPoints, TakeProfitPoints). Cuando son positivos se convierten a compensaciones de precio usando el PriceStep del instrumento y se pasan a StartProtection.
Salida basada en tiempo – el EA original cierra posiciones que exceden un tiempo de mantenimiento (TimeTrade, nTime). En StockSharp esto se maneja mediante UseTimeExit y HoldingLimit. La salida se evalúa antes que las señales del indicador en cada vela finalizada.
Temporización de posición – la estrategia registra la marca de tiempo de la última operación que resultó en una posición larga o corta. Estas marcas de tiempo se usan para la salida basada en tiempo.
Parámetros
Parámetro
Descripción
Length
Longitud de ambas pasadas LWMA que forman el canal.
SignalBar
Desplazamiento de la barra examinada para señales (0 = última vela cerrada).
CandleType
Marco temporal utilizado para el indicador y la evaluación de operaciones.
OrderVolume
Volumen utilizado al enviar nuevas órdenes de entrada.
StopLossPoints
Distancia de stop-loss en puntos del instrumento (0 deshabilita el stop).
TakeProfitPoints
Distancia de take-profit en puntos del instrumento (0 deshabilita el objetivo).
EnableBuyEntries
Permitir o prohibir nuevas posiciones largas.
EnableSellEntries
Permitir o prohibir nuevas posiciones cortas.
EnableBuyExits
Permitir que el indicador cierre posiciones largas.
EnableSellExits
Permitir que el indicador cierre posiciones cortas.
UseTimeExit
Habilitar el cierre de posiciones después de que transcurra HoldingLimit.
HoldingLimit
Tiempo máximo de mantenimiento antes de que se active la salida por tiempo.
Notas
El canal se calcula a partir de los máximos y mínimos de las velas exactamente como el indicador MQL incluido AbsolutelyNoLagLwma_Range_Channel.
La estrategia ignora las velas incompletas y trabaja solo con datos completados para evitar señales prematuras.
Establecer SignalBar en 0 coincide con la configuración típica de MT5 donde se analiza la última vela cerrada. Valores más altos reproducen la confirmación retardada utilizada por el EA predeterminado (SignalBar = 1).
Si PriceStep no está disponible para el instrumento seleccionado, los desplazamientos de stop-loss y take-profit se ignoran, preservando el comportamiento de las entradas con valor cero en el script original.
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>
/// LWMA range channel breakout strategy.
/// Uses fast/slow WMA crossover with mid-channel exit logic.
/// </summary>
public class AbsolutelyNoLagLwmaRangeChannelTmPlusStrategy : 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 AbsolutelyNoLagLwmaRangeChannelTmPlusStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 10)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast WMA period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 30)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow WMA 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 fastWma = new WeightedMovingAverage { Length = FastPeriod };
var slowWma = new WeightedMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastWma, slowWma, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastWma);
DrawIndicator(area, slowWma);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fast;
_prevSlow = slow;
return;
}
if (_prevFast == null || _prevSlow == null)
{
_prevFast = fast;
_prevSlow = slow;
return;
}
var prevAbove = _prevFast.Value > _prevSlow.Value;
var currAbove = fast > slow;
_prevFast = fast;
_prevSlow = slow;
// Crossover: fast crosses above slow → buy
if (!prevAbove && currAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Crossover: fast crosses below slow → sell
else if (prevAbove && !currAbove)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
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 WeightedMovingAverage
from StockSharp.Algo.Strategies import Strategy
class absolutely_no_lag_lwma_range_channel_tm_plus_strategy(Strategy):
def __init__(self):
super(absolutely_no_lag_lwma_range_channel_tm_plus_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 Period", "Fast WMA period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 30) \
.SetDisplay("Slow Period", "Slow WMA 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(absolutely_no_lag_lwma_range_channel_tm_plus_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(absolutely_no_lag_lwma_range_channel_tm_plus_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_slow = None
fast_wma = WeightedMovingAverage()
fast_wma.Length = self.FastPeriod
slow_wma = WeightedMovingAverage()
slow_wma.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_wma, slow_wma, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_wma)
self.DrawIndicator(area, slow_wma)
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:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif prev_above and not curr_above:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
def CreateClone(self):
return absolutely_no_lag_lwma_range_channel_tm_plus_strategy()