Открыть на GitHub

Стратегия Exp Digital MACD

Обзор

Стратегия Exp Digital MACD переносит логику экспертного советника MetaTrader 5 «Exp_Digital_MACD» в инфраструктуру StockSharp. Она подписывается на свечи выбранного таймфрейма и реагирует на форму и расположение MACD‑осциллятора. В коде сохранены четыре режима работы:

  1. Breakdown – торговля на пробой нулевой линии осциллятора.
  2. MACD Twist – фиксация разворота наклона линии MACD.
  3. Signal Twist – использование разворота сигнальной линии как подтверждения.
  4. MACD Disposition – анализ расположения MACD относительно сигнальной линии.

В библиотеке StockSharp отсутствует оригинальный фильтр «Digital MACD», поэтому применяется стандартный индикатор MovingAverageConvergenceDivergenceSignal. Значения EMA по умолчанию (12/26) и длина сигнальной EMA (5) подобраны для максимального сходства с MQL-реализацией, где Signal_XMA = 5. Стратегия обрабатывает только закрытые свечи и хранит минимальную историю в приватных полях, повторяя поведение SignalBar = 1.

Параметры

  • Mode – выбор торгового алгоритма из четырёх доступных. По умолчанию: MacdTwist.
  • FastPeriod – период быстрой EMA в расчёте MACD. По умолчанию: 12.
  • SlowPeriod – период медленной EMA. По умолчанию: 26.
  • SignalPeriod – период EMA сигнальной линии. По умолчанию: 5.
  • CandleType – тип свечей, который будет подписан (по умолчанию – 4 часа).
  • OrderVolume – объём каждой рыночной заявки.
  • StopLossPoints / TakeProfitPoints – защитные отступы в шагах цены. При наличии корректного Security.Step переводятся в абсолютные значения; ноль выключает защиту.
  • EnableLongEntry / EnableShortEntry – разрешение на открытие длинных или коротких позиций.
  • EnableLongExit / EnableShortExit – разрешение на закрытие уже открытых позиций соответствующего направления.

Логика торговли

Алгоритм оценивает значения индикаторов на закрытии каждой свечи:

  • Breakdown: если два бара назад значение MACD было выше нуля, стратегия при необходимости закрывает короткие позиции и открывает длинную, когда следующий бар опускается к нулю или ниже. Если два бара назад MACD был ниже нуля, система закрывает длинные позиции и открывает короткие при обратном пересечении. Это повторяет контртрендовую логику исходника вокруг нулевой линии.
  • MACD Twist: анализирует три последних значения MACD. Локальный минимум (value[2] > value[1], value[0] > value[1]) формирует сигнал на покупку, локальный максимум – на продажу. Противоположный разворот служит сигналом выхода.
  • Signal Twist: идентичная проверка применяется к сигнальной линии.
  • MACD Disposition: сравнивает MACD и сигнальную линию. Если раньше MACD находился выше сигнальной линии, а затем опустился к ней или ниже, стратегия покупает и закрывает шорты; при обратном пересечении продаёт и закрывает лонги.

Каждый вход выполняется рыночной заявкой объёмом OrderVolume + |Position|, что позволяет одновременно развернуть и открыть позицию. Сигналы выхода отправляют рыночные заявки только на закрытие текущего объёма.

Управление рисками

При запуске вызывается StartProtection. Если заданы положительные значения StopLossPoints и/или TakeProfitPoints и у инструмента известен шаг цены, стоп‑приказы выставляются в абсолютных значениях. Нулевые параметры отключают автоматическую защиту.

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

  • Стратегия оценивает только последнюю завершённую свечу, аналогично SignalBar = 1 в MQL.
  • Разница между стандартным MACD и оригинальным Digital MACD сохраняется; при необходимости можно подстроить периоды EMA.
  • Все комментарии в исходнике на английском языке согласно требованию.

Использование

  1. Привяжите стратегию к нужному счёту и инструменту, предоставляющему свечи выбранного таймфрейма.
  2. Настройте параметры под ликвидность и волатильность инструмента.
  3. Запустите стратегию – она автоматически подпишется на свечи, рассчитает MACD и будет размещать заявки в соответствии с выбранным режимом.
  4. Отслеживайте логи или график (при наличии), чтобы контролировать значения индикатора и изменения позиции.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Digital MACD strategy using fast/slow EMA crossover (MACD concept).
/// Trades on MACD line zero crossovers.
/// </summary>
public class ExpDigitalMacdStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;

	private decimal? _prevMacd;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int FastPeriod
	{
		get => _fastPeriod.Value;
		set => _fastPeriod.Value = value;
	}

	public int SlowPeriod
	{
		get => _slowPeriod.Value;
		set => _slowPeriod.Value = value;
	}

	public ExpDigitalMacdStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast EMA for MACD", "Indicators");

		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow EMA for MACD", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMacd = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevMacd = null;

		var fastEma = new ExponentialMovingAverage { Length = FastPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fastEma);
			DrawIndicator(area, slowEma);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevMacd = fast - slow;
			return;
		}

		var macd = fast - slow;

		if (_prevMacd == null)
		{
			_prevMacd = macd;
			return;
		}

		// MACD crosses above zero → buy
		if (_prevMacd.Value <= 0 && macd > 0)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		// MACD crosses below zero → sell
		else if (_prevMacd.Value >= 0 && macd < 0)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_prevMacd = macd;
	}
}