Esta estratégia é um port StockSharp do especialista MetaTrader "Exp_ColorXDerivative". Funciona em um período de velas configurável (velas de 12 horas por padrão) e analisa o histograma de momentum ColorXDerivative. O indicador mede a velocidade de mudança da fonte de preço escolhida durante um deslocamento fixo, suaviza o resultado com uma média móvel e, em seguida, classifica cada barra em um de cinco estados de cor. As operações seguem a mesma lógica que no EA original: o robô compra quando o momentum de alta se acelera ou um movimento de baixa começa a contrair, e vende quando a pressão de baixa aumenta ou uma perna de alta perde força.
Lógica do Indicador
Converter cada vela para o AppliedPrice selecionado (fechamento, abertura, fechamento ponderado, Demark, etc.).
Calcular a derivada de preço: (price[0] - price[shift]) * 100 / shift, onde shift = DerivativePeriod.
Suavizar a derivada com o método selecionado (SMA, EMA, SMMA, LWMA ou Jurik). A média móvel Jurik padrão reproduz o suavização JJMA da implementação MQL.
Atribuir um estado de cor:
0 – derivada > 0 e crescendo (forte aceleração de alta).
1 – derivada > 0 mas caindo (momentum de alta perdendo força).
2 – derivada ≈ 0 (neutro).
3 – derivada < 0 mas crescendo (movimento de baixa se contraindo).
4 – derivada < 0 e caindo (aceleração de baixa).
Um deslocamento de sinal controla qual barra finalizada é avaliada (1 = última barra fechada, 2 = barra anterior, etc.).
Regras de Trading
Entrada comprada: habilitada quando EnableLongEntry é verdadeiro e:
a cor atual é 0 enquanto a cor anterior não era 0 (momentum vira fortemente de alta), ou
a cor atual é 3 enquanto a cor anterior era 4 ou 2 (movimento de baixa começa a contrair).
Entrada vendida: habilitada quando EnableShortEntry é verdadeiro e:
a cor atual é 4 enquanto a cor anterior não era 4 (aceleração de baixa começa), ou
a cor atual é 1 enquanto a cor anterior era 0 ou 2 (movimento de alta desvanece).
Saída comprada: acionada quando a cor atual é 1 ou 4 e EnableLongExit é verdadeiro.
Saída vendida: acionada quando a cor atual é 0 ou 3 e EnableShortExit é verdadeiro.
Ordens são enviadas como ordens a mercado usando o parâmetro OrderVolume. Fechamentos de posição são executados antes de novas entradas para emular a lógica sequencial do EA original.
Gestão de Risco
Distâncias opcionais de stop loss e take profit são fornecidas via StopLossTicks e TakeProfitTicks. Quando qualquer valor está acima de zero, a estratégia chama StartProtection, convertendo ticks em passos de preço usando o tamanho Step do instrumento. A proteção de stop/alvo é executada uma vez e é compatível com auto-trading ou backtesting.
Parâmetros
OrderVolume – tamanho da ordem a mercado.
CandleType – período para os cálculos do indicador (padrão: período de 12 horas).
DerivativePeriod – distância em barras usada para o deslocamento da derivada.
AppliedPrice – fonte de preço passada para a derivada (fechamento, mediana, ponderado, Demark, etc.).
SmoothingMethod – filtro de suavização aplicado à derivada. Valores suportados: SMA, EMA, SMMA, LWMA, Jurik.
SmoothingLength – período do filtro de suavização.
SignalShift – quantas barras finalizadas atrás ler os valores de cor (1 = barra fechada mais recente).
StopLossTicks / TakeProfitTicks – distâncias de proteção opcionais em passos do instrumento.
EnableLongEntry, EnableShortEntry, EnableLongExit, EnableShortExit – alternâncias correspondentes às entradas originais do EA.
Notas
A estratégia reproduz a lógica orientada por indicador do EA MetaTrader sem recursos adicionais de gestão de dinheiro.
A suavização Jurik é a aproximação mais próxima do filtro JJMA usado na biblioteca MQL; outras opções mapeiam para as médias móveis padrão do StockSharp.
O histórico de cores é armazenado internamente para que a otimização em SignalShift funcione exatamente como na versão MetaTrader.
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>
/// Color X Derivative strategy (simplified). Uses Momentum to detect
/// acceleration/deceleration and generate reversal signals.
/// </summary>
public class ColorXDerivativeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumLength;
private readonly StrategyParam<int> _emaLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumLength
{
get => _momentumLength.Value;
set => _momentumLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public ColorXDerivativeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_momentumLength = Param(nameof(MomentumLength), 34)
.SetGreaterThanZero()
.SetDisplay("Momentum Length", "Derivative lookback", "Indicators");
_emaLength = Param(nameof(EmaLength), 7)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "Smoothing period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var momentum = new Momentum { Length = MomentumLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
decimal prevMom = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, ema, (ICandleMessage candle, decimal momValue, decimal emaValue) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevMom = momValue;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevMom = momValue;
return;
}
var close = candle.ClosePrice;
// Momentum turning positive with price above EMA
if (prevMom <= 0 && momValue > 0 && close > emaValue && Position <= 0)
BuyMarket();
// Momentum turning negative with price below EMA
else if (prevMom >= 0 && momValue < 0 && close < emaValue && Position >= 0)
SellMarket();
prevMom = momValue;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 Momentum, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class color_x_derivative_strategy(Strategy):
def __init__(self):
super(color_x_derivative_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._momentum_length = self.Param("MomentumLength", 34) \
.SetDisplay("Momentum Length", "Derivative lookback", "Indicators")
self._ema_length = self.Param("EmaLength", 7) \
.SetDisplay("EMA Length", "Smoothing period", "Indicators")
self._prev_mom = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumLength(self):
return self._momentum_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
def OnReseted(self):
super(color_x_derivative_strategy, self).OnReseted()
self._prev_mom = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(color_x_derivative_strategy, self).OnStarted2(time)
self._prev_mom = 0.0
self._has_prev = False
momentum = Momentum()
momentum.Length = self.MomentumLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(momentum, ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value, ema_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self._has_prev:
self._prev_mom = mv
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_mom = mv
return
close = float(candle.ClosePrice)
ev = float(ema_value)
if self._prev_mom <= 0 and mv > 0 and close > ev and self.Position <= 0:
self.BuyMarket()
elif self._prev_mom >= 0 and mv < 0 and close < ev and self.Position >= 0:
self.SellMarket()
self._prev_mom = mv
def CreateClone(self):
return color_x_derivative_strategy()