Esta estrategia porta el asesor experto original Exp_XWAMI_NN3_MMRec.mq5 a StockSharp. Tres capas independientes (A/B/C) ejecutan el indicador de momento XWAMI en diferentes marcos temporales y combinan sus señales dentro de una única posición neteada. Cada capa emula el MagicNumber correspondiente de la versión MetaTrader, incluyendo su contador de gestión de dinero y los niveles de protección.
Lógica de trading
Para cada capa se calcula una serie de momento como precio - precio[iPeriod] usando el precio aplicado seleccionado. La diferencia se pasa a través de cuatro suavizadores secuenciales (métodos y longitudes configurables) para obtener las líneas "up" y "down" del indicador XWAMI.
Las señales se evalúan en el desplazamiento SignalBar. Cuando la barra anterior tenía up > down, los cortos de esa capa se cierran y se permite una entrada larga si la barra más reciente muestra up <= down. Cuando la barra anterior tenía up < down, los largos se cierran y se permite una entrada corta cuando up >= down.
Antes de abrir en una nueva dirección, la estrategia aplana todas las posiciones opuestas de otras capas para respetar el modelo de neteo de StockSharp. Esto refleja el comportamiento de cerrar una operación de magic-number opuesto en el código MQL.
Los niveles opcionales de stop-loss y take-profit (expresados en puntos de precio) se verifican en cada vela completada usando el máximo/mínimo de la vela. Si se alcanzan, fuerzan una salida inmediata de esa capa.
Contador de gestión de dinero
Cada capa mantiene un historial continuo de sus operaciones más recientes. Cada vez que el número de pérdidas dentro del período de retroceso configurado alcanza el LossTrigger, el tamaño de posición cambia del volumen normal al volumen reducido ("Small"). Las operaciones exitosas o conteos de pérdidas menores revierten al tamaño normal. Las direcciones de compra y venta mantienen sus propios contadores, exactamente como en el asistente MMRec original.
Parámetros
La estrategia expone el conjunto completo de parámetros del experto MQL:
Layer?CandleType – tipo de vela (marco temporal) usado por la capa (predeterminados: A=8h, B=4h, C=1h).
Layer?Period – retardo usado para construir la serie de momento.
Layer?Method1..4, Layer?Length1..4, Layer?Phase1..4 – configuración de suavizado para las cuatro etapas XWAMI.
Layer?SignalBar – desplazamiento de la barra de señal (0 = actual, 1 = última barra cerrada, predeterminado 1).
Layer?AllowBuy/SellOpen y Layer?AllowBuy/SellClose – permisos para entradas y salidas.
Layer?NormalVolume, Layer?SmallVolume – tamaño de operación en lotes (o unidades) para modos normal y reducido.
Layer?BuyTotalTrigger, Layer?BuyLossTrigger, Layer?SellTotalTrigger, Layer?SellLossTrigger – contadores MMRec que controlan el cambio al volumen reducido.
Layer?StopLossPoints, Layer?TakeProfitPoints – niveles de protección en puntos de precio (0 desactiva el nivel).
Notas
La versión StockSharp usa una única posición neta. Cuando dos capas discrepan, las posiciones opuestas se cierran antes de entrar en la nueva, preservando el orden previsto de señales mientras se evita el hedging.
La etapa Tillson T3 está implementada directamente en C# para mantener paridad con el algoritmo de suavizado original. Otros modos de suavizado se mapean a los indicadores integrados de StockSharp (SMA, EMA, SMMA/RMA, LWMA, Jurik).
Dado que las consultas de historial de operaciones difieren entre plataformas, la lógica MMRec rastrea operaciones completadas dentro de la estrategia y reproduce los mismos umbrales sin escanear el historial del terminal.
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>
/// XWAMI multi-layer strategy using triple WMA for trend alignment.
/// </summary>
public class XwamiMultiLayerMmrecStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _midPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast;
private decimal? _prevMid;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int MidPeriod
{
get => _midPeriod.Value;
set => _midPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public XwamiMultiLayerMmrecStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 8)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast WMA", "Indicators");
_midPeriod = Param(nameof(MidPeriod), 21)
.SetGreaterThanZero()
.SetDisplay("Mid Period", "Medium WMA", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 50)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow WMA", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevFast = null;
_prevMid = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevFast = null;
_prevMid = null;
var fast = new ExponentialMovingAverage { Length = FastPeriod };
var mid = new ExponentialMovingAverage { Length = MidPeriod };
var slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fast, mid, slow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fast);
DrawIndicator(area, mid);
DrawIndicator(area, slow);
DrawOwnTrades(area);
}
}
private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal midVal, decimal slowVal)
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
_prevFast = fastVal;
_prevMid = midVal;
return;
}
if (_prevFast == null || _prevMid == null)
{
_prevFast = fastVal;
_prevMid = midVal;
return;
}
// Fast crosses above mid with trend alignment (fast > slow)
if (_prevFast.Value <= _prevMid.Value && fastVal > midVal && fastVal > slowVal)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
// Fast crosses below mid with trend alignment (fast < slow)
else if (_prevFast.Value >= _prevMid.Value && fastVal < midVal && fastVal < slowVal)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
_prevFast = fastVal;
_prevMid = midVal;
}
}
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 xwami_multi_layer_mmrec_strategy(Strategy):
def __init__(self):
super(xwami_multi_layer_mmrec_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", 8) \
.SetDisplay("Fast Period", "Fast WMA", "Indicators")
self._mid_period = self.Param("MidPeriod", 21) \
.SetDisplay("Mid Period", "Medium WMA", "Indicators")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow WMA", "Indicators")
self._prev_fast = None
self._prev_mid = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastPeriod(self):
return self._fast_period.Value
@property
def MidPeriod(self):
return self._mid_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
def OnReseted(self):
super(xwami_multi_layer_mmrec_strategy, self).OnReseted()
self._prev_fast = None
self._prev_mid = None
def OnStarted2(self, time):
super(xwami_multi_layer_mmrec_strategy, self).OnStarted2(time)
self._prev_fast = None
self._prev_mid = None
fast = ExponentialMovingAverage()
fast.Length = self.FastPeriod
mid = ExponentialMovingAverage()
mid.Length = self.MidPeriod
slow = ExponentialMovingAverage()
slow.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast, mid, slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast)
self.DrawIndicator(area, mid)
self.DrawIndicator(area, slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, mid_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
mv = float(mid_value)
sv = float(slow_value)
if self._prev_fast is None or self._prev_mid is None:
self._prev_fast = fv
self._prev_mid = mv
return
# Fast crosses above mid with trend alignment (fast > slow)
if self._prev_fast <= self._prev_mid and fv > mv and fv > sv:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
# Fast crosses below mid with trend alignment (fast < slow)
elif self._prev_fast >= self._prev_mid and fv < mv and fv < sv:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_mid = mv
def CreateClone(self):
return xwami_multi_layer_mmrec_strategy()