Esta estrategia replica el experto de MetaTrader 5 Exp_XDeMarker_Histogram_Vol_Direct usando la API de alto nivel de StockSharp. Multiplica el oscilador XDeMarker por el flujo de volumen elegido, suaviza tanto el oscilador como el volumen con el mismo promedio móvil, y compara el resultado con niveles superiores/inferiores configurables. Las decisiones de trading se toman cuando el histograma suavizado cambia de dirección entre barras consecutivas.
Lógica del indicador
Calcular el oscilador XDeMarker clásico en el marco temporal seleccionado.
Escalar el oscilador por el conteo de ticks o el volumen real para cada vela finalizada.
Suavizar tanto el histograma como el volumen con el tipo de promedio móvil seleccionado.
Multiplicar el volumen suavizado por los multiplicadores de nivel configurados para obtener cuatro bandas dinámicas.
Detectar la dirección del histograma (subiendo o bajando). Cuando la dirección cambia, la estrategia abre una nueva posición en la dirección correspondiente mientras también cierra cualquier operación opuesta.
El método de suavizado soporta promedios móviles simples, exponenciales, suavizados (RMA/SMMA) y ponderados. Los filtros exóticos de la biblioteca original (JJMA, JurX, ParMA, T3, VIDYA, AMA) no están disponibles en este port.
Reglas de trading
Entrada larga — habilitada cuando Allow Long Entry = true. Si la barra anterior tenía dirección "arriba" y la última barra cambió a "abajo", la estrategia apunta a una posición larga de Volume lotes.
Entrada corta — habilitada cuando Allow Short Entry = true. Activada cuando la barra anterior era "abajo" y la última barra gira "arriba".
Salida larga — habilitada cuando Allow Long Exit = true. Si la dirección de la barra anterior es "abajo", la posición se liquida a menos que se dispare una nueva entrada corta en la misma barra.
Salida corta — habilitada cuando Allow Short Exit = true. Activada cuando la dirección de la barra anterior es "arriba".
Las señales se evalúan una vez por vela finalizada. La implementación de StockSharp mantiene el retardo original de una barra; el parámetro Signal Bar está presente como referencia pero los valores distintos de 1 se ignoran con una advertencia.
Parámetros
Parámetro
Descripción
Candle Type
Marco temporal utilizado para construir velas para el indicador.
DeMarker Period
Período de retrospectiva para el oscilador XDeMarker base.
Volume Source
Elegir entre conteo de ticks y volumen real negociado.
High Level 2 / High Level 1
Multiplicadores aplicados al volumen suavizado para formar bandas superiores.
Low Level 1 / Low Level 2
Multiplicadores para bandas inferiores.
Smoothing Method
Tipo de promedio móvil aplicado tanto al histograma como al volumen.
Smoothing Length
Longitud de la ventana de suavizado.
Smoothing Phase
Marcador de posición de compatibilidad (no se usa pero se mantiene para paridad).
Signal Bar
Desplazamiento histórico, fijo en 1 igual que en el experto.
Allow Long/Short Entry
Habilitar la apertura de posiciones en la dirección respectiva.
Allow Long/Short Exit
Habilitar el cierre automático de operaciones existentes.
Notas de implementación
La clase XDeMarkerHistogramVolDirectIndicator reproduce los buffers del indicador MT5 y expone el histograma suavizado, las bandas y los flags de dirección a través de un valor de indicador complejo.
Cuando se requiere una nueva exposición objetivo, la estrategia envía una única orden de mercado que mueve la posición actual al nivel deseado (Volume, -Volume o plano). Esto imita las llamadas secuenciales de cierre/apertura en el código MQL5 original sin duplicar órdenes.
El renderizado del gráfico traza automáticamente las velas, el indicador personalizado y las operaciones ejecutadas cuando hay un área de gráfico disponible.
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()