Открыть на GitHub

Стратегия Day Opening MACD Histogram

Общее описание

Стратегия воспроизводит логику советника MetaTrader «2 1000 1 0.7% 0.5 500lev st»: позиция открывается в начале каждого нового торгового дня, а направление выбирается по наклону гистограммы MACD. Система рассчитана на часовые свечи и использует фиксированные параметры управления капиталом из исходного MQL файла.

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

  • Стратегия анализирует часовые свечи и определяет первую свечу каждого торгового дня.
  • Для фильтрации направления используются значения гистограммы MACD на двух последних завершённых свечах предыдущего дня.
  • Если гистограмма между этими свечами снизилась, в начале нового дня открывается длинная позиция.
  • Если гистограмма выросла, открывается короткая позиция.
  • Одновременно может быть открыта только одна позиция. При появлении обратного сигнала текущая позиция закрывается перед открытием новой.

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

  • Первоначальный стоп-лосс: 875 пунктов (переводится в цену умножением на шаг цены инструмента).
  • Тейк-профит: 510 пунктов.
  • Трейлинг-стоп: 2172 пункта. Стоп следует за максимумом (для длинных) или минимумом (для коротких) с момента входа и заменяет первоначальный стоп, если становится ближе к цене.
  • Функция переноса стопа в безубыток в исходной версии отключена и здесь также не используется.

Параметры

Название Описание Значение по умолчанию
CandleType Тип свечей (по умолчанию часовые). Часовые свечи
MacdFastPeriod Период быстрой EMA в MACD. 58
MacdSlowPeriod Период медленной EMA в MACD. 195
MacdSignalPeriod Период сигнальной линии MACD. 183
StopLossPoints Дистанция стоп-лосса в пунктах. 875
TakeProfitPoints Дистанция тейк-профита в пунктах. 510
TrailingStopPoints Дистанция трейлинг-стопа в пунктах. 2172

Примечания

  • Используются только закрытые свечи, что соответствует опции «Use previous bar value» в оригинальной реализации и исключает подглядывание в будущее.
  • Управление стопами и трейлингом выполняется самой стратегией, поэтому дополнительные защитные механизмы портфеля лучше не включать, чтобы избежать дублирования.
  • Параметры рассчитаны на стандартное определение пункта. При работе с инструментами с другим шагом цены скорректируйте значения.
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;
	}
}