Открыть на GitHub

Стратегия MACD Candle

Данная стратегия является конверсией советника MetaTrader «Exp_MACDCandle». Она преобразует цвет свечей индикатора MACD Candle в торговые сигналы с использованием высокоуровневого API StockSharp.

Концепция

Индикатор MACD Candle строит синтетические свечи из значений MACD, вычисленных по ценам открытия и закрытия. Если MACD по закрытию выше MACD по открытию, свеча считается бычьей (цвет 2). Обратное состояние формирует медвежью свечу (цвет 0). При равных значениях появляется нейтральный цвет (1).

Стратегия открывает длинную позицию, когда после небычьей свечи появляется бычья. Короткая позиция открывается, когда после немедвежьей свечи возникает медвежья. Текущая позиция переворачивается в новую сторону.

Параметры

  • FastLength – период быстрой EMA для MACD (по умолчанию 12).
  • SlowLength – период медленной EMA для MACD (по умолчанию 26).
  • SignalLength – период сигнальной линии MACD (по умолчанию 9).
  • CandleType – тип свечей для расчётов, по умолчанию TimeFrameCandle с периодом четыре часа.

Все параметры настраиваются и поддерживают оптимизацию.

Правила входа и выхода

  • Вход в лонг: MACD по закрытию выше MACD по открытию, а предыдущая свеча не была бычьей.
  • Вход в шорт: MACD по открытию выше MACD по закрытию, а предыдущая свеча не была медвежьей.
  • Выход: позиция закрывается при появлении противоположного сигнала; стоп‑лосс и тейк‑профит не используются.

Примечания

  • В стратегии применяются рыночные заявки (BuyMarket и SellMarket).
  • Сигналы рассчитываются только по завершённым свечам, чтобы избежать шума.
  • Пример предназначен для учебных целей и не содержит управления рисками.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy based on the MACD Candle indicator.
/// Compares MACD computed on opens vs closes.
/// </summary>
public class MacdCandleStrategy : Strategy
{
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<DataType> _candleType;

	private MovingAverageConvergenceDivergenceSignal _macdOpen;
	private MovingAverageConvergenceDivergenceSignal _macdClose;
	private decimal? _previousColor;

	public int FastLength { get => _fastLength.Value; set => _fastLength.Value = value; }
	public int SlowLength { get => _slowLength.Value; set => _slowLength.Value = value; }
	public int SignalLength { get => _signalLength.Value; set => _signalLength.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public MacdCandleStrategy()
	{
		_fastLength = Param(nameof(FastLength), 12)
			.SetGreaterThanZero()
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicator")
			.SetOptimize(8, 16, 2);

		_slowLength = Param(nameof(SlowLength), 26)
			.SetGreaterThanZero()
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicator")
			.SetOptimize(20, 40, 2);

		_signalLength = Param(nameof(SignalLength), 9)
			.SetGreaterThanZero()
			.SetDisplay("Signal", "Signal period", "Indicator")
			.SetOptimize(5, 15, 1);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candle type for indicators", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_previousColor = null;
		_macdOpen = default;
		_macdClose = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_macdOpen = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = FastLength },
				LongMa = { Length = SlowLength },
			},
			SignalMa = { Length = SignalLength }
		};

		_macdClose = new MovingAverageConvergenceDivergenceSignal
		{
			Macd =
			{
				ShortMa = { Length = FastLength },
				LongMa = { Length = SlowLength },
			},
			SignalMa = { Length = SignalLength }
		};

		Indicators.Add(_macdOpen);
		Indicators.Add(_macdClose);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ProcessCandle)
			.Start();
	}

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

		var openInput = new DecimalIndicatorValue(_macdOpen, candle.OpenPrice, candle.OpenTime) { IsFinal = true };
		var closeInput = new DecimalIndicatorValue(_macdClose, candle.ClosePrice, candle.OpenTime) { IsFinal = true };

		var openValue = _macdOpen.Process(openInput);
		var closeValue = _macdClose.Process(closeInput);

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var openMacd = ((IMovingAverageConvergenceDivergenceSignalValue)openValue).Macd;
		var closeMacd = ((IMovingAverageConvergenceDivergenceSignalValue)closeValue).Macd;

		if (openMacd == null || closeMacd == null)
			return;

		var color = openMacd < closeMacd ? 2m : openMacd > closeMacd ? 0m : 1m;

		if (_previousColor is null)
		{
			_previousColor = color;
			return;
		}

		if (color == 2m && _previousColor < 2m)
		{
			if (Position < 0)
				BuyMarket();
			if (Position <= 0)
				BuyMarket();
		}
		else if (color == 0m && _previousColor > 0m)
		{
			if (Position > 0)
				SellMarket();
			if (Position >= 0)
				SellMarket();
		}

		_previousColor = color;
	}
}