Esta estratégia replica o expert do MetaTrader 5 Exp_XDeMarker_Histogram_Vol_Direct usando a API de alto nível do StockSharp. Ela multiplica o oscilador XDeMarker pelo fluxo de volume escolhido, suaviza tanto o oscilador quanto o volume com o mesmo promedio móvel, e compara o resultado com níveis superiores/inferiores configuráveis. As decisões de negociação são tomadas quando o histograma suavizado muda de direção entre barras consecutivas.
Lógica do indicador
Calcular o oscilador XDeMarker clássico no período selecionado.
Escalar o oscilador pela contagem de ticks ou volume real para cada candle finalizado.
Suavizar tanto o histograma quanto o volume com o tipo de média móvel selecionado.
Multiplicar o volume suavizado pelos multiplicadores de nível configurados para obter quatro bandas dinâmicas.
Detectar a direção do histograma (subindo ou caindo). Quando a direção muda, a estratégia abre uma nova posição na direção correspondente enquanto também fecha qualquer operação oposta.
O método de suavização suporta médias móveis simples, exponenciais, suavizadas (RMA/SMMA) e ponderadas. Os filtros exóticos da biblioteca original (JJMA, JurX, ParMA, T3, VIDYA, AMA) não estão disponíveis neste port.
Regras de negociação
Entrada comprada — habilitada quando Allow Long Entry = true. Se a barra anterior tinha direção "para cima" e a última barra mudou para "para baixo", a estratégia mira uma posição comprada de Volume lotes.
Entrada vendida — habilitada quando Allow Short Entry = true. Acionada quando a barra anterior estava "para baixo" e a barra mais recente gira "para cima".
Saída comprada — habilitada quando Allow Long Exit = true. Se a direção da barra anterior é "para baixo", a posição é liquidada, a menos que uma nova entrada vendida seja disparada na mesma barra.
Saída vendida — habilitada quando Allow Short Exit = true. Ativada quando a direção da barra anterior é "para cima".
Os sinais são avaliados uma vez por candle finalizado. A implementação do StockSharp mantém o atraso original de uma barra; o parâmetro Signal Bar está presente como referência, mas valores diferentes de 1 são ignorados com um aviso.
Parâmetros
Parâmetro
Descrição
Candle Type
Período usado para construir candles para o indicador.
DeMarker Period
Período de retrospectiva para o oscilador XDeMarker base.
Volume Source
Escolher entre contagem de ticks e volume real negociado.
High Level 2 / High Level 1
Multiplicadores aplicados ao volume suavizado para formar bandas superiores.
Low Level 1 / Low Level 2
Multiplicadores para bandas inferiores.
Smoothing Method
Tipo de média móvel aplicado tanto ao histograma quanto ao volume.
Smoothing Length
Comprimento da janela de suavização.
Smoothing Phase
Marcador de posição de compatibilidade (não usado, mas mantido para paridade).
Signal Bar
Deslocamento histórico, fixo em 1 como no expert.
Allow Long/Short Entry
Habilitar abertura de posições na direção respectiva.
Allow Long/Short Exit
Habilitar fechamento automático de operações existentes.
Notas de implementação
A classe XDeMarkerHistogramVolDirectIndicator reproduz os buffers do indicador MT5 e expõe o histograma suavizado, as bandas e os flags de direção através de um valor de indicador complexo.
Quando uma nova exposição alvo é necessária, a estratégia envia uma única ordem de mercado que move a posição atual para o nível desejado (Volume, -Volume ou flat). Isso imita as chamadas sequenciais de fechamento/abertura no código MQL5 original sem duplicar ordens.
O renderizador de gráfico traça automaticamente os candles, o indicador personalizado e as operações executadas quando uma área de gráfico está disponível.
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 XDeMarkerHistogramVolDirectStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _period;
private decimal? _prevDm;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int Period { get => _period.Value; set => _period.Value = value; }
public XDeMarkerHistogramVolDirectStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
_period = Param(nameof(Period), 14).SetGreaterThanZero().SetDisplay("DeMarker Period", "DeMarker lookback", "Indicators");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevDm = null;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevDm = null;
var dm = new DeMarker { Length = Period };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(dm, ProcessCandle).Start();
var area = CreateChartArea();
if (area != null) { DrawCandles(area, subscription); DrawOwnTrades(area); }
}
private void ProcessCandle(ICandleMessage candle, decimal dmVal)
{
if (candle.State != CandleStates.Finished) return;
if (!IsFormedAndOnlineAndAllowTrading()) { _prevDm = dmVal; return; }
if (_prevDm == null) { _prevDm = dmVal; return; }
if (_prevDm.Value < 0.45m && dmVal >= 0.55m && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
else if (_prevDm.Value > 0.55m && dmVal <= 0.45m && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
_prevDm = dmVal;
}
}
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 DeMarker
from StockSharp.Algo.Strategies import Strategy
class x_de_marker_histogram_vol_direct_strategy(Strategy):
def __init__(self):
super(x_de_marker_histogram_vol_direct_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._period = self.Param("Period", 14) \
.SetDisplay("DeMarker Period", "DeMarker lookback", "Indicators")
self._prev_dm = None
@property
def CandleType(self):
return self._candle_type.Value
@property
def Period(self):
return self._period.Value
def OnReseted(self):
super(x_de_marker_histogram_vol_direct_strategy, self).OnReseted()
self._prev_dm = None
def OnStarted2(self, time):
super(x_de_marker_histogram_vol_direct_strategy, self).OnStarted2(time)
self._prev_dm = None
dm = DeMarker()
dm.Length = self.Period
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(dm, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawOwnTrades(area)
def _on_process(self, candle, dm_value):
if candle.State != CandleStates.Finished:
return
dv = float(dm_value)
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_dm = dv
return
if self._prev_dm is None:
self._prev_dm = dv
return
if self._prev_dm < 0.45 and dv >= 0.55 and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif self._prev_dm > 0.55 and dv <= 0.45 and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_dm = dv
def CreateClone(self):
return x_de_marker_histogram_vol_direct_strategy()