Esta estrategia reproduce la lógica del asesor experto original de MetaTrader "Exp_2XMA_Ichimoku_Oscillator" combinando dos envolventes de precio estilo Ichimoku suavizadas con medias móviles configurables. La implementación en StockSharp utiliza la API de estrategia de alto nivel y se centra en la generación de señales basada en velas, manteniendo las reglas de gestión de posición del algoritmo fuente.
Idea principal
Se calculan dos puntos medios tipo Donchian en el marco temporal seleccionado:
El punto medio rápido promedia el máximo más alto y el mínimo más bajo en UpPeriod1 y DownPeriod1 barras.
El punto medio lento realiza la misma operación con UpPeriod2 y DownPeriod2 barras.
Cada punto medio es suavizado por una media móvil (Method1, Method2) de longitudes XLength1 y XLength2. Los métodos de suavizado disponibles son Simple, Exponencial, Suavizado y Ponderado Lineal.
El valor del oscilador es la diferencia entre los dos puntos medios suavizados. Cuatro estados de color describen su comportamiento:
PositiveRising (0): el oscilador está por encima de cero y sube.
PositiveFalling (1): el oscilador está por encima de cero y pierde impulso.
NegativeRising (3): el oscilador está por debajo de cero pero sube hacia cero.
NegativeFalling (4): el oscilador está por debajo de cero y cae más.
Neutral (2) se asigna durante el calentamiento.
Las señales se evalúan usando los colores de la barra en SignalBar y la barra inmediatamente anterior (SignalBar + 1), lo que refleja el desplazamiento de búfer en la versión MQL.
Lógica de trading
Entrada larga: permitida cuando EnableBuyOpen es verdadero. Si el color de la barra más antigua (SignalBar + 1) era ascendente (0 o 3) y la barra más reciente (SignalBar) cambió a un color descendente (1 o 4), la estrategia cierra cualquier posición corta (EnableSellClose) y abre/extiende una posición larga usando Volume + |Position| unidades.
Entrada corta: permitida cuando EnableSellOpen es verdadero. Si el color de la barra más antigua era descendente (1 o 4) y la barra más reciente cambió a un color ascendente (0 o 3), la estrategia cierra los largos existentes (EnableBuyClose) y abre/extiende una posición corta con Volume + |Position| unidades.
Todas las ejecuciones ocurren al cierre de la vela que genera la señal. Las órdenes son siempre de mercado y la estrategia no aplica niveles adicionales de stop-loss o take-profit; depende únicamente de las transiciones de color para las salidas.
StartProtection() se activa al inicio para usar las verificaciones de seguridad integradas del framework para posiciones inesperadas.
Parámetros
Nombre
Descripción
Predeterminado
CandleType
Marco temporal utilizado para los cálculos del indicador.
Velas de 4 horas
UpPeriod1, DownPeriod1
Ventanas de retrospectiva para el punto medio rápido.
6, 6
UpPeriod2, DownPeriod2
Ventanas de retrospectiva para el punto medio lento.
9, 9
XLength1, XLength2
Longitudes de suavizado para las dos medias móviles.
25, 80
Method1, Method2
Tipos de media móvil (Simple, Exponencial, Suavizado, Ponderado).
Simple
SignalBar
Desplazamiento de barra histórica usado para leer colores del oscilador.
1
EnableBuyOpen, EnableSellOpen
Activar entradas largas/cortas.
true
EnableBuyClose, EnableSellClose
Activar salidas largas/cortas.
true
Volume
Tamaño base de operación; las posiciones existentes se suman a este valor al revertir.
1
Notas de uso
Los tipos de media móvil cubren los comportamientos de suavizado más comunes del experto original. Las opciones avanzadas como los ajustes de fase XMA personalizados no están disponibles en StockSharp y fueron reemplazadas con indicadores estándar.
Dado que el oscilador se calcula en velas cerradas, las señales aparecen con el mismo retraso de una barra que usaba la implementación MQL (SignalBar = 1). Aumente SignalBar si necesita barras de confirmación adicionales.
Considere combinar la estrategia con gestión de riesgo externa (gestor de cartera, stops protectores) cuando opere en mercados en vivo, ya que las salidas dependen exclusivamente de las reversiones de color del oscilador.
namespace StockSharp.Samples.Strategies;
using System;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// Exp 2XMA Ichimoku Oscillator strategy (simplified).
/// Uses two SMAs of different periods as a crossover oscillator.
/// Buys when fast SMA crosses above slow SMA, sells when fast crosses below.
/// </summary>
public class Exp2XmaIchimokuOscillatorStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
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 Exp2XmaIchimokuOscillatorStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Source candles", "General");
_fastPeriod = Param(nameof(FastPeriod), 5)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast moving average length", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 20)
.SetGreaterThanZero()
.SetDisplay("Slow Period", "Slow moving average length", "Indicators");
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastMa = new ExponentialMovingAverage { Length = FastPeriod };
var slowMa = new ExponentialMovingAverage { Length = SlowPeriod };
decimal prevFast = 0, prevSlow = 0;
bool prevInitialized = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastMa, slowMa, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastValue;
prevSlow = slowValue;
prevInitialized = true;
return;
}
if (!prevInitialized)
{
prevFast = fastValue;
prevSlow = slowValue;
prevInitialized = true;
return;
}
// Buy on bullish crossover
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
{
BuyMarket();
}
// Sell on bearish crossover
else if (prevFast >= prevSlow && fastValue < slowValue && Position >= 0)
{
SellMarket();
}
prevFast = fastValue;
prevSlow = slowValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, fastMa);
DrawIndicator(area, slowMa);
DrawOwnTrades(area);
}
}
}
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 exp2_xma_ichimoku_oscillator_strategy(Strategy):
def __init__(self):
super(exp2_xma_ichimoku_oscillator_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Source candles", "General")
self._fast_period = self.Param("FastPeriod", 5) \
.SetDisplay("Fast Period", "Fast moving average length", "Indicators")
self._slow_period = self.Param("SlowPeriod", 20) \
.SetDisplay("Slow Period", "Slow moving average length", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
@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(exp2_xma_ichimoku_oscillator_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
def OnStarted2(self, time):
super(exp2_xma_ichimoku_oscillator_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._prev_initialized = False
fast_ma = ExponentialMovingAverage()
fast_ma.Length = self.FastPeriod
slow_ma = ExponentialMovingAverage()
slow_ma.Length = self.SlowPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription \
.Bind(fast_ma, slow_ma, self._on_process) \
.Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ma)
self.DrawIndicator(area, slow_ma)
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 not self.IsFormedAndOnlineAndAllowTrading():
self._prev_fast = fv
self._prev_slow = sv
self._prev_initialized = True
return
if not self._prev_initialized:
self._prev_fast = fv
self._prev_slow = sv
self._prev_initialized = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return exp2_xma_ichimoku_oscillator_strategy()