Открыть на GitHub

Стратегия XDeMarker Histogram Vol Direct

Стратегия переносит советник MetaTrader 5 Exp_XDeMarker_Histogram_Vol_Direct на инфраструктуру StockSharp. Она умножает осциллятор DeMarker на выбранный поток объёма, сглаживает и сам осциллятор, и объём одним и тем же методом усреднения, после чего сравнивает результат с динамическими уровнями. Сделки совершаются, когда направление сглаженной гистограммы меняется между последовательными барами.

Логика индикатора

  1. Рассчитывается классический DeMarker на заданном таймфрейме.
  2. Значение DeMarker домножается на тиковый либо реальный объём каждой закрытой свечи.
  3. Гистограмма и объём сглаживаются выбранным типом скользящей средней.
  4. Сглаженный объём умножается на четыре коэффициента, образуя верхние и нижние уровни.
  5. По направлению (рост/падение) гистограммы определяется, требуется ли смена позиции. При смене направления открывается сделка в новом направлении и закрывается противоположная.

Варианты сглаживания включают простую, экспоненциальную, сглаженную (RMA/SMMA) и линейно-взвешенную средние. Экзотические фильтры из оригинальной библиотеки (JJMA, JurX, ParMA, T3, VIDYA, AMA) в этой реализации отсутствуют.

Торговые правила

  • Вход в лонг — возможен при Разрешить вход в лонг = true. Если позапрошлый бар имел направление «вверх», а последний переключился на «вниз», стратегия выставляет целевую длинную позицию объёмом Volume.
  • Вход в шорт — доступен при Разрешить вход в шорт = true. Условие зеркальное: предыдущий бар «вниз», текущий «вверх».
  • Выход из лонга — при Разрешить выход из лонга = true позиция закрывается, если направление предыдущего бара «вниз» и нет одновременного сигнала на открытие шорта.
  • Выход из шорта — аналогично, при Разрешить выход из шорта = true позиция закрывается, если предыдущий бар «вверх» и нет сигнала на открытие лонга.

Расчёт сигналов выполняется один раз для каждой завершённой свечи. Сохранена оригинальная задержка в один бар — параметр Signal Bar оставлен для совместимости, но значения, отличные от 1, игнорируются с предупреждением.

Параметры

Параметр Описание
Candle Type Таймфрейм свечей для расчёта индикатора.
DeMarker Period Длина базового осциллятора DeMarker.
Volume Source Источник объёма: число тиков или фактический объём.
High Level 2 / High Level 1 Множители для построения верхних динамических уровней.
Low Level 1 / Low Level 2 Множители для нижних уровней.
Smoothing Method Тип скользящей средней для сглаживания гистограммы и объёма.
Smoothing Length Длина окна сглаживания.
Smoothing Phase Заглушка для совместимости, в расчётах не используется.
Signal Bar Смещение по истории (жёстко равно 1).
Allow Long/Short Entry Разрешения на открытие длинных и коротких позиций.
Allow Long/Short Exit Разрешения на автоматическое закрытие позиций.

Особенности реализации

  • Класс XDeMarkerHistogramVolDirectIndicator воспроизводит буферы индикатора MT5 и отдаёт сглаженную гистограмму, уровни и направление через комплексное значение индикатора.
  • При необходимости изменить целевую позицию стратегия отправляет единственный рыночный ордер, приводящий позицию к значениям Volume, -Volume или 0. Это повторяет последовательность «закрыть+открыть» из MQL5 без дублирования заявок.
  • При наличии области графика автоматически отображаются свечи, индикатор и совершённые сделки.
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;
	}
}