La estrategia recrea el experto de doble marco temporal "Exp_ColorX2MA_X2" para StockSharp. Utiliza dos filtros ColorX2MA: un mapa de tendencia en el marco temporal superior y un disparador de entrada en el marco temporal inferior. Ambos valores ColorX2MA se construyen encadenando dos medias móviles configurables y luego coloreando el resultado según la pendiente actual. Las decisiones de trading se ejecutan cuando el color del marco temporal inferior cambia en la dirección de la tendencia del marco temporal superior.
La implementación soporta las opciones de precio aplicado originales y los modos de suavizado más comunes (SMA, EMA, SMMA, LWMA, Jurik). Cuando el indicador Jurik expone una propiedad Phase, se actualiza con el valor de fase configurado.
Reglas de Trading
Entrada en largo
El color ColorX2MA del marco temporal superior es alcista (trend direction > 0).
El color ColorX2MA del marco temporal inferior cambió de alcista en la barra anterior a neutro o bajista en la última barra completada (Clr[1] == 1 y Clr[0] != 1).
El trading en largo está habilitado.
Entrada en corto
El color ColorX2MA del marco temporal superior es bajista (trend direction < 0).
El color ColorX2MA del marco temporal inferior cambió de bajista en la barra anterior a neutro o alcista en la última barra completada (Clr[1] == 2 y Clr[0] != 2).
El trading en corto está habilitado.
Salida en largo
Cuando aparece un color bajista en el marco temporal inferior (Clr[1] == 2) y el permiso de cierre de largo secundario está habilitado, o la tendencia del marco temporal superior gira bajista con el permiso de cierre de largo primario habilitado.
Salida en corto
Cuando aparece un color alcista en el marco temporal inferior (Clr[1] == 1) y el permiso de cierre de corto secundario está habilitado, o la tendencia del marco temporal superior gira alcista con el permiso de cierre de corto primario habilitado.
Stops
Las distancias opcionales de stop loss y take profit se especifican en puntos (multiplicadas por el paso de precio del instrumento). Se evalúan en cada vela de señal finalizada comparando los extremos de la vela con el precio promedio de la posición.
Valores predeterminados
Marco temporal de tendencia: velas de 6 horas.
Marco temporal de señal: velas de 30 minutos.
Suavizado de tendencia: SMA(12) alimentando a Jurik(5, fase 15).
Suavizado de señal: SMA(12) alimentando a Jurik(5, fase 15).
Precio aplicado: Cierre.
Desplazamiento de señal: 1 barra en ambos marcos temporales.
Permisos: entradas y salidas en largo/corto habilitadas.
Stop loss: 1000 puntos (convertido usando el paso de precio).
Take profit: 2000 puntos (convertido usando el paso de precio).
Filtros y Notas
Dirección: opera en largo y corto, controlado mediante indicadores de permiso.
Marco temporal: doble marco temporal (tendencia en HTF, entradas en LTF).
Indicadores: ColorX2MA de dos niveles con métodos de suavizado configurables.
Soporte de suavizado: Sma, Ema, Smma, Lwma, Jurik. Otros modos de la librería original no están implementados.
Precios aplicados: las 12 fórmulas originales incluyendo precios TrendFollow y Demark.
Stops: stop loss y take profit opcionalmente a distancia fija.
Complejidad: intermedio porque sincroniza dos marcos temporales y búferes de color.
Adecuado para: configuraciones de seguimiento de tendencia en FX, índices o cripto donde se prefiere el indicador ColorX2MA.
Consejos de Uso
Mantener el marco temporal superior significativamente mayor que el marco temporal de señal para evitar whipsaws frecuentes.
Ajustar el parámetro de desplazamiento de señal (SignalSignalBar) para reaccionar más rápido o aumentarlo para suavizar más.
Si el instrumento no provee PriceStep, las distancias de stop/take se interpretan directamente en unidades de precio.
El suavizado Jurik requiere un paquete de indicadores StockSharp con licencia; cuando no esté disponible, la estrategia funciona con las otras opciones de suavizado.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// ColorX2MA X2 strategy (simplified). Uses dual EMA smoothing to detect trend color transitions.
/// Buys when the smoothed MA turns up, sells when it turns down.
/// </summary>
public class ExpColorX2MaX2Strategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastLength;
private readonly StrategyParam<int> _slowLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int FastLength
{
get => _fastLength.Value;
set => _fastLength.Value = value;
}
public int SlowLength
{
get => _slowLength.Value;
set => _slowLength.Value = value;
}
public ExpColorX2MaX2Strategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_fastLength = Param(nameof(FastLength), 12)
.SetGreaterThanZero()
.SetDisplay("Fast Length", "Fast EMA period", "Indicators");
_slowLength = Param(nameof(SlowLength), 26)
.SetGreaterThanZero()
.SetDisplay("Slow Length", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var fastEma = new ExponentialMovingAverage { Length = FastLength };
var slowEma = new ExponentialMovingAverage { Length = SlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(fastEma, slowEma, (ICandleMessage candle, decimal fastValue, decimal slowValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastValue;
prevSlow = slowValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastValue;
prevSlow = slowValue;
return;
}
// Fast crosses above slow
if (prevFast <= prevSlow && fastValue > slowValue && Position <= 0)
BuyMarket();
// Fast crosses below slow
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, fastEma);
DrawIndicator(area, slowEma);
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 exp_color_x2_ma_x2_strategy(Strategy):
def __init__(self):
super(exp_color_x2_ma_x2_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._fast_length = self.Param("FastLength", 12) \
.SetDisplay("Fast Length", "Fast EMA period", "Indicators")
self._slow_length = self.Param("SlowLength", 26) \
.SetDisplay("Slow Length", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def FastLength(self):
return self._fast_length.Value
@property
def SlowLength(self):
return self._slow_length.Value
def OnReseted(self):
super(exp_color_x2_ma_x2_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(exp_color_x2_ma_x2_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
fast_ema = ExponentialMovingAverage()
fast_ema.Length = self.FastLength
slow_ema = ExponentialMovingAverage()
slow_ema.Length = self.SlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(fast_ema, slow_ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, fast_ema)
self.DrawIndicator(area, slow_ema)
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._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = 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 exp_color_x2_ma_x2_strategy()