Estratégia Color Schaff JCCX Trend Cycle MMRec Duplex
Visão geral
Recria o Expert Advisor bidirecional "ColorSchaffJCCXTrendCycle_MMRec_Duplex" do MetaTrader dentro do StockSharp.
Usa dois stacks independentes de Schaff Trend Cycle construídos sobre médias móveis Jurik para detectar reversões de alta e de baixa.
Implementa um módulo MMRec simplificado (recomendador de gestão monetária) que reduz o tamanho após perdas repetidas.
Aplica conjuntos de parâmetros separados para operações compradas e vendidas, possibilitando configurações assimétricas entre períodos e fontes de preço.
Pipeline de indicadores
Aproximação JCCX – cada preço é processado por uma média móvel Jurik para obter uma série detendenciada. A série detendenciada e seu valor absoluto são suavizados novamente com médias Jurik para aproximar o oscilador JCCX original.
Camada MACD – a diferença entre as saídas JCCX rápida e lenta fornece a base de momentum.
Transformação estocástica dupla – janelas deslizantes de mínimo/máximo normalizam o momentum MACD e produzem o valor final do Schaff Trend Cycle (STC) no intervalo -100..+100.
Controle de fase – o parâmetro Phase modula um fator de suavização interno (0.05–0.95) aplicado após cada etapa estocástica, emulando o comportamento de "fase" do Jurik.
O stack de indicadores é executado duas vezes: uma para o bloco comprado e uma para o bloco vendido. Cada bloco pode usar diferentes tipos de candles e entradas de preço.
Lógica de negociação
Bloco comprado
Entrada: quando o STC comprado cruza acima de zero (valor atual > 0 e o valor anterior atrasado ≤ 0). Posições vendidas existentes são fechadas primeiro.
Saída: quando o STC comprado cai abaixo de zero e as saídas compradas estão habilitadas.
Stops: distâncias opcionais de stop-loss e take-profit (expressas em passos de preço) são avaliadas em cada candle concluído usando máximas/mínimas do candle.
Bloco vendido
Entrada: quando o STC vendido cruza abaixo de zero (valor atual < 0 e o valor atrasado ≥ 0). Qualquer posição comprada existente é encerrada antes de abrir uma posição vendida.
Saída: quando o STC vendido sobe acima de zero e as saídas vendidas estão habilitadas.
Stops: verificações simétricas de stop-loss e take-profit para operações vendidas.
O parâmetro SignalBar define quantos candles completamente fechados são ignorados antes de os sinais serem avaliados. Um valor de 1 reproduz o comportamento do MetaTrader de usar o candle concluído anterior.
Gestão monetária (MMRec)
Duas filas rastreiam os resultados de operações mais recentes para comprados e vendidos.
TotalTrigger limita o comprimento da fila; apenas os últimos N resultados são considerados.
LossTrigger define quantas perdas dentro dessa fila mudam o tamanho da operação para SmallVolume.
Quando o limite de perdas não é ultrapassado, a estratégia usa NormalVolume.
Parâmetros
Grupo
Parâmetro
Descrição
Padrão
Long
LongCandleType
Tipo de candle (período) para cálculos comprados.
Período de 8 horas
Long
LongFastLength
Comprimento Jurik rápido na aproximação JCCX comprada.
23
Long
LongSlowLength
Comprimento Jurik lento para a aproximação JCCX comprada.
50
Long
LongSmoothLength
Comprimento de suavização Jurik aplicado ao numerador/denominador.
8
Long
LongPhase
Parâmetro de fase traduzido em fator de suavização (0.05–0.95).
100
Long
LongCycle
Comprimento da janela deslizante para as transformações estocásticas.
10
Long
LongSignalBar
Atraso (em barras) antes de um sinal ser avaliado.
1
Long
LongAppliedPrice
Fonte de preço para cálculos comprados.
Close
Long
LongAllowOpen / LongAllowClose
Habilitar/desabilitar entradas ou saídas compradas.
true
Long
LongTotalTrigger
Número de operações compradas recentes armazenadas para a fila MMRec.
5
Long
LongLossTrigger
Perdas necessárias dentro da fila para mudar para volume pequeno.
3
Long
LongSmallVolume / LongNormalVolume
Tamanhos de operação comprada reduzido e padrão.
0.01 / 0.1
Long
LongStopLoss / LongTakeProfit
Distâncias opcionais de stop/take em passos de preço.
1000 / 2000
Short
Igual ao comprado (com prefixo Short).
Notas de risco
Os passos de preço são obtidos do Security atual. Certifique-se de que o instrumento tem um PriceStep válido ou ajuste os parâmetros adequadamente.
As verificações de stop-loss e take-profit são avaliadas em candles concluídos; a qualidade de execução intrabarra depende da resolução do candle.
O módulo MMRec depende da comparação de preços de entrada e saída. Em negociação ao vivo, o slippage pode alterar o resultado efetivo.
Dicas de uso
Comece com configurações idênticas de comprado/vendido para emular o EA duplex original, depois experimente com períodos assimétricos.
Reduza SignalBar para zero para respostas mais rápidas; aumente-o para filtrar ruído.
Otimize LongPhase/ShortPhase junto com os comprimentos de suavização para ajustar a capacidade de resposta versus suavidade.
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()