This strategy replicates the MetaTrader 5 expert Exp_XDeMarker_Histogram_Vol_Direct using StockSharp's high-level API. It
multiplies the DeMarker oscillator by the chosen volume stream, smooths both the oscillator and the volume with the same moving
average, and compares the result with configurable upper/lower levels. Trading decisions are made when the smoothed histogram
changes direction between consecutive bars.
Indicator logic
Calculate the classic DeMarker oscillator on the selected timeframe.
Scale the oscillator by tick count or real volume for each finished candle.
Smooth both the histogram and the volume with the selected moving-average type.
Multiply the smoothed volume by the configured level multipliers to obtain four dynamic bands.
Detect the histogram direction (rising or falling). When the direction flips, the strategy opens a new position in the
corresponding direction while also closing any opposite trade.
The smoothing method supports simple, exponential, smoothed (RMA/SMMA) and weighted moving averages. Exotic filters from the
original library (JJMA, JurX, ParMA, T3, VIDYA, AMA) are not available in this port.
Trading rules
Long entry – enabled when Allow Long Entry = true. If the previous bar had an "up" direction and the last bar switched to
"down", the strategy targets a long position of Volume lots.
Short entry – enabled when Allow Short Entry = true. Triggered when the previous bar was "down" and the latest bar turns
"up".
Long exit – enabled when Allow Long Exit = true. If the previous bar direction is "down", the position is flattened unless
a new short entry is fired in the same bar.
Short exit – enabled when Allow Short Exit = true. Activated when the previous bar direction is "up".
Signals are evaluated once per finished candle. The StockSharp implementation keeps the original one-bar delay; the Signal Bar
parameter is present for reference but values different from 1 are ignored with a warning.
Parameters
Parameter
Description
Candle Type
Timeframe used to build candles for the indicator.
DeMarker Period
Lookback for the base DeMarker oscillator.
Volume Source
Choose between tick count and real traded volume.
High Level 2 / High Level 1
Multipliers applied to the smoothed volume to form upper bands.
Low Level 1 / Low Level 2
Multipliers for lower bands.
Smoothing Method
Moving-average type applied to both the histogram and the volume.
Smoothing Length
Length of the smoothing window.
Smoothing Phase
Compatibility placeholder (not used but kept for parity).
Signal Bar
Historical offset, fixed to 1 just like in the expert.
Allow Long/Short Entry
Enable opening positions in the respective direction.
Allow Long/Short Exit
Enable automatic closure of existing trades.
Implementation notes
The XDeMarkerHistogramVolDirectIndicator class reproduces the MT5 indicator buffers and exposes the smoothed histogram,
bands and direction flags through a complex indicator value.
When a new target exposure is required, the strategy sends a single market order that moves the current position to the desired
level (Volume, -Volume or flat). This mimics the sequential close/open calls in the original MQL5 code without duplicating
orders.
Chart rendering automatically plots the candles, the custom indicator and the executed trades when a chart area is available.
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()