View on GitHub

Day Opening MACD Histogram Strategy

Overview

This strategy replicates the MetaTrader expert "2 1000 1 0.7% 0.5 500lev st" by entering a trade at the beginning of each new trading day and filtering the direction with the MACD histogram slope. The system was designed for hourly candles and relies on fixed money management parameters converted from the original MQL settings.

Trading Logic

  • The strategy monitors hourly candles and detects the first candle of every new day.
  • It evaluates the MACD histogram on the two most recent completed candles of the previous day.
  • If the histogram declined between those two bars, the system opens a long position at the first candle of the new day.
  • If the histogram increased, it opens a short position instead.
  • Only one position can be active at a time. Opposite signals close the current trade before opening the new direction.

Risk Management

  • Initial stop-loss distance: 875 points (converted to price by multiplying with the instrument price step).
  • Take-profit distance: 510 points.
  • Trailing stop distance: 2172 points. The stop follows the highest (long) or lowest (short) price reached since the entry and overrides the initial stop when it becomes tighter.
  • The original break-even option was disabled and therefore omitted here.

Parameters

Name Description Default
CandleType Candle series used by the strategy (hourly by default). 1 hour candles
MacdFastPeriod Fast EMA period for the MACD. 58
MacdSlowPeriod Slow EMA period for the MACD. 195
MacdSignalPeriod Signal line period for the MACD. 183
StopLossPoints Stop-loss distance expressed in instrument points. 875
TakeProfitPoints Take-profit distance in points. 510
TrailingStopPoints Trailing stop distance in points. 2172

Notes

  • The strategy uses only completed candles to avoid intrabar look-ahead, mirroring the "Use previous bar value" option from the source expert.
  • Trailing and fixed exits are handled internally, so additional portfolio protections should remain disabled to prevent double handling of stops.
  • The logic assumes the broker uses standard point definitions (price step). Adjust the parameters if the instrument uses a different tick size.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// Day Opening MACD Histogram strategy: MACD histogram direction.
/// Buys when MACD histogram turns positive, sells when turns negative.
/// </summary>
public class DayOpeningMacdHistogramStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _signalPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevHistogram;
	private int _candlesSinceTrade;
	private bool _hasPrev;

	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 int SignalPeriod { get => _signalPeriod.Value; set => _signalPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public DayOpeningMacdHistogramStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 12)
			.SetGreaterThanZero()
			.SetDisplay("MACD Fast", "MACD fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 26)
			.SetGreaterThanZero()
			.SetDisplay("MACD Slow", "MACD slow EMA period", "Indicators");
		_signalPeriod = Param(nameof(SignalPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("Signal Period", "MACD signal period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 4)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between trades", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevHistogram = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevHistogram = 0;
		_candlesSinceTrade = SignalCooldownCandles;
		_hasPrev = false;
		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;

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
		if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;

		var histogram = macdMain - signal;

		if (_hasPrev)
		{
			if (_prevHistogram <= 0 && histogram > 0 && Position <= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				BuyMarket();
				_candlesSinceTrade = 0;
			}
			else if (_prevHistogram >= 0 && histogram < 0 && Position >= 0 && _candlesSinceTrade >= SignalCooldownCandles)
			{
				SellMarket();
				_candlesSinceTrade = 0;
			}
		}

		_prevHistogram = histogram;
		_hasPrev = true;
	}
}