Открыть на GitHub

Стратегия MACD Signal Crossover

Обзор

Этот пример демонстрирует перенос эксперта MetaTrader 4 MACD_v1.mq4 в высокоуровневый API StockSharp. Алгоритм отслеживает пересечения линии MACD и сигнальной линии, открывая сделки в сторону нового импульса. Дополнительно реализованы те же защитные механизмы, что и в исходном советнике: удалённый тейк-профит, стоп-лосс и частичная фиксация прибыли при достижении первой цели.

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

  1. Источник данных – стратегия подписывается на выбранный таймфрейм (по умолчанию 5-минутные свечи) и привязывает индикатор MovingAverageConvergenceDivergenceSignal.
  2. Условия входа:
    • Покупка при пересечении линии MACD выше сигнальной. Если есть короткая позиция, она закрывается перед открытием лонга.
    • Продажа при пересечении MACD ниже сигнальной линии. Текущая длинная позиция закрывается перед открытием шорта.
  3. Условия выхода:
    • Обратное пересечение закрывает открытую позицию и инициирует разворот.
    • StartProtection управляет стоп-лоссом и тейк-профитом в пунктах, повторяя параметры оригинальной реализации.
    • Частичное закрытие половины позиции происходит один раз, когда цена проходит заданное количество пунктов от средней цены входа.

Параметры

Название Значение по умолчанию Описание
Fast Period 23 Длина быстрой EMA в расчёте MACD (соответствует параметру a = 2300).
Slow Period 40 Длина медленной EMA (параметр b = 4000).
Signal Period 8 Длина сигнальной средней (c = 800).
Take Profit 500 Расстояние тейк-профита в пунктах. Ноль отключает защитный тейк.
Stop Loss 80 Расстояние стоп-лосса в пунктах. Ноль отключает стоп.
Partial Profit 70 Расстояние в пунктах до частичного закрытия половины позиции. Ноль отменяет функцию.
Candle Type 5-минутный таймфрейм Тип свечей для расчёта индикатора.

Дополнительные замечания

  • В оригинале периоды MACD задавались в сотых долях (2300/4000/800). В версии StockSharp они переведены в привычные значения 23/40/8.
  • Флаг частичного выхода автоматически сбрасывается при наборе новой позиции, что позволяет повторно использовать цель.
  • При наличии панели графика стратегия рисует свечи, линии MACD и собственные сделки.
  • Объём сделок задаётся свойством Volume базовой стратегии. Перед запуском подберите его под требования инструмента.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class MacdSignalCrossoverStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private bool _prevMacdAboveSignal;
	private bool _hasPrev;

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

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

	public int SignalPeriod
	{
		get => _signalPeriod.Value;
		set => _signalPeriod.Value = value;
	}

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

	public MacdSignalCrossoverStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 23);
		_slowPeriod = Param(nameof(SlowPeriod), 40);
		_signalPeriod = Param(nameof(SignalPeriod), 8);
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame());
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_prevMacdAboveSignal = false;
		_hasPrev = false;
	}

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

		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = FastPeriod },
				LongMa = { Length = SlowPeriod },
			},
			SignalMa = { Length = SignalPeriod }
		};

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(macd, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!macdValue.IsFinal)
			return;

		var macdTyped = macdValue as MovingAverageConvergenceDivergenceSignalValue;
		if (macdTyped == null)
			return;

		var macdLine = macdTyped.Macd;
		var signalLine = macdTyped.Signal;

		if (macdLine == null || signalLine == null)
			return;

		var isMacdAboveSignal = macdLine.Value > signalLine.Value;

		if (!_hasPrev)
		{
			_hasPrev = true;
			_prevMacdAboveSignal = isMacdAboveSignal;
			return;
		}

		var crossedAbove = isMacdAboveSignal && !_prevMacdAboveSignal;
		var crossedBelow = !isMacdAboveSignal && _prevMacdAboveSignal;

		if (crossedAbove)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (crossedBelow)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_prevMacdAboveSignal = isMacdAboveSignal;
	}
}