Estrategia Color Schaff JCCX Trend Cycle MMRec Duplex
Descripción general
Recrea el Asesor Experto bidireccional "ColorSchaffJCCXTrendCycle_MMRec_Duplex" de MetaTrader dentro de StockSharp.
Utiliza dos cadenas independientes de Schaff Trend Cycle basadas en medias móviles Jurik para detectar reversiones alcistas y bajistas.
Implementa un módulo simplificado MMRec (recomendador de gestión monetaria) que reduce el tamaño tras pérdidas repetidas.
Aplica conjuntos de parámetros separados para operaciones largas y cortas, permitiendo configuraciones asimétricas entre marcos temporales y fuentes de precio.
Cadena de indicadores
Aproximación JCCX – cada precio se procesa con una media móvil Jurik para obtener una serie detendenciada. La serie detendenciada y su valor absoluto se suavizan de nuevo con medias Jurik para aproximar el oscilador JCCX original.
Capa MACD – la diferencia entre las salidas JCCX rápida y lenta proporciona la base de momentum.
Doble transformación estocástica – ventanas deslizantes de mínimo/máximo normalizan el momentum MACD y producen el valor final de Schaff Trend Cycle (STC) en el rango -100..+100.
Control de fase – el parámetro Phase modula un factor de suavizado interno (0.05–0.95) aplicado tras cada paso estocástico, emulando el comportamiento de "fase" de Jurik.
La cadena de indicadores se ejecuta dos veces: una para el bloque largo y otra para el bloque corto. Cada bloque puede usar diferentes tipos de velas y entradas de precio.
Lógica de trading
Bloque largo
Entrada: cuando el STC largo cruza por encima de cero (valor actual > 0 y el valor previo retardado ≤ 0). Las posiciones cortas existentes se cierran primero.
Salida: cuando el STC largo cae por debajo de cero y las salidas largas están habilitadas.
Stops: las distancias opcionales de stop-loss y take-profit (expresadas en pasos de precio) se evalúan en cada vela completada usando máximos/mínimos de vela.
Bloque corto
Entrada: cuando el STC corto cruza por debajo de cero (valor actual < 0 y el valor retardado ≥ 0). Cualquier posición larga existente se liquida antes de abrir una posición corta.
Salida: cuando el STC corto sube por encima de cero y las salidas cortas están habilitadas.
Stops: verificaciones simétricas de stop-loss y take-profit para operaciones cortas.
El parámetro SignalBar define cuántas velas completamente cerradas se omiten antes de evaluar las señales. Un valor de 1 reproduce el comportamiento de MetaTrader de usar la vela completada anterior.
Gestión monetaria (MMRec)
Dos colas rastrean los resultados de operaciones más recientes para largos y cortos.
TotalTrigger limita la longitud de la cola; solo se consideran los últimos N resultados.
LossTrigger define cuántas pérdidas dentro de esa cola cambian el tamaño de la operación a SmallVolume.
Cuando no se supera el umbral de pérdidas, la estrategia usa NormalVolume.
Parámetros
Grupo
Parámetro
Descripción
Por defecto
Long
LongCandleType
Tipo de vela (marco temporal) para cálculos largos.
Marco temporal de 8 horas
Long
LongFastLength
Longitud Jurik rápida en la aproximación JCCX larga.
23
Long
LongSlowLength
Longitud Jurik lenta para la aproximación JCCX larga.
50
Long
LongSmoothLength
Longitud de suavizado Jurik aplicada al numerador/denominador.
8
Long
LongPhase
Parámetro de fase traducido en factor de suavizado (0.05–0.95).
100
Long
LongCycle
Longitud de ventana deslizante para las transformaciones estocásticas.
10
Long
LongSignalBar
Retardo (en barras) antes de evaluar una señal.
1
Long
LongAppliedPrice
Fuente de precio para cálculos largos.
Close
Long
LongAllowOpen / LongAllowClose
Habilitar/deshabilitar entradas o salidas largas.
true
Long
LongTotalTrigger
Número de operaciones largas recientes almacenadas para la cola MMRec.
5
Long
LongLossTrigger
Pérdidas requeridas en la cola para cambiar a volumen pequeño.
3
Long
LongSmallVolume / LongNormalVolume
Tamaños de operación larga reducido y predeterminado.
0.01 / 0.1
Long
LongStopLoss / LongTakeProfit
Distancias opcionales de stop/take en pasos de precio.
1000 / 2000
Short
Igual que largo (con prefijo Short).
Notas de riesgo
Los pasos de precio se obtienen del Security actual. Asegúrese de que el instrumento tenga un PriceStep válido o ajuste los parámetros en consecuencia.
Las verificaciones de stop-loss y take-profit se evalúan en velas completadas; la calidad de ejecución intrabarra depende de la resolución de la vela.
El módulo MMRec depende de la comparación de precios de entrada y salida. En trading en vivo, el deslizamiento puede alterar el resultado efectivo.
Consejos de uso
Comience con configuraciones idénticas de largo/corto para emular el EA duplex original, luego experimente con marcos temporales asimétricos.
Reduzca SignalBar a cero para respuestas más rápidas; auméntelo para filtrar ruido.
Optimice LongPhase/ShortPhase junto con las longitudes de suavizado para ajustar la capacidad de respuesta frente a la suavidad.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class ColorSchaffJccxTrendCycleMmrecDuplexStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private decimal? _prevFast, _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 ColorSchaffJccxTrendCycleMmrecDuplexStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_fastPeriod = Param(nameof(FastPeriod), 12).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast period", "Indicators");
_slowPeriod = Param(nameof(SlowPeriod), 26).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow period", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(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 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;
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 color_schaff_jccx_trend_cycle_mmrec_duplex_strategy(Strategy):
def __init__(self):
super(color_schaff_jccx_trend_cycle_mmrec_duplex_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", 12) \
.SetDisplay("Fast EMA", "Fast period", "Indicators")
self._slow_period = self.Param("SlowPeriod", 26) \
.SetDisplay("Slow EMA", "Slow 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(color_schaff_jccx_trend_cycle_mmrec_duplex_strategy, self).OnReseted()
self._prev_fast = None
self._prev_slow = None
def OnStarted2(self, time):
super(color_schaff_jccx_trend_cycle_mmrec_duplex_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 color_schaff_jccx_trend_cycle_mmrec_duplex_strategy()