Открыть на GitHub

Стратегия MACD Divergence RSI

Обзор

  • Порт советника MetaTrader «Macd diver rsi mt4» на высокоуровневый API StockSharp.
  • Использует фильтры RSI и поиск дивергенций MACD для работы с разворотами на одном инструменте.
  • В рынке может находиться только одна позиция; новые сигналы рассматриваются только при нулевой позиции.

Логика сигналов

  1. Каждая закрывшаяся свеча выбранного таймфрейма обновляет четыре связанных индикатора:
    • Два независимых RelativeStrengthIndex для зон перепроданности и перекупленности, значения берутся с предыдущей свечи.
    • Два MovingAverageConvergenceDivergence с настраиваемыми периодами EMA и сигнальной линии.
  2. Условия для покупки
    • RSI предыдущей свечи должен быть ниже заданного порога перепроданности.
    • Последовательность значений MACD должна сформировать локальную впадину ниже динамического порога (эквивалент трёх пунктов для текущего инструмента).
    • История MACD и цен просматривается в поисках предыдущей впадины и соответствующего ценового минимума. Дивергенция подтверждается, когда MACD растёт, а цена обновляет минимум (обычная дивергенция), либо MACD снижается, а цена формирует более высокий минимум (скрытая дивергенция), что полностью повторяет алгоритм MQL.
    • При выполнении условий и отсутствии открытой позиции отправляется рыночная покупка с отдельными параметрами объёма и риск-менеджмента для лонга.
  3. Условия для продажи зеркальны: используется порог перекупленности RSI и поиск пиков MACD, сравниваются предыдущие и текущий ценовые максимумы.
  4. После входа расстояния стоп-лосса и тейк-профита, заданные в пунктах, переводятся в абсолютную цену (с учётом правил point format) и передаются в SetStopLoss / SetTakeProfit.

Параметры

  • LowerRsiPeriod, LowerRsiThresholdinp1_Lo_RSIperiod / inp1_Ro_Value.
  • BullishFastEma, BullishSlowEma, BullishSignalSmainp2_fastEMA / inp2_slowEMA / inp2_signalSMA.
  • BullishVolume, BullishStopLossPips, BullishTakeProfitPipsinp3_VolumeSize / inp3_StopLossPips / inp3_TakeProfitPips.
  • UpperRsiPeriod, UpperRsiThresholdinp4_Lo_RSIperiod / inp4_Ro_Value.
  • BearishFastEma, BearishSlowEma, BearishSignalSmainp5_fastEMA / inp5_slowEMA / inp5_signalSMA.
  • BearishVolume, BearishStopLossPips, BearishTakeProfitPipsinp6_VolumeSize / inp6_StopLossPips / inp6_TakeProfitPips.
  • CandleType – таймфрейм, на основе которого выполняются все расчёты.

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

  • Порог дивергенции MACD рассчитывается по текущему шагу цены и равен трём пунктам, что соответствует значению 0.0003 в исходном MQL.
  • История свечей, MACD и цен хранится в списках ограниченной длины (до 600 элементов), что позволяет повторить окна поиска дивергенций без лишних выделений памяти.
  • Подписка SubscribeCandles(...).Bind(...) обновляет все индикаторы в одном обработчике, стратегия работает только с завершёнными свечами — аналогично блоку Once per bar в оригинале.
  • Расстояния стоп-лосса и тейк-профита переводятся из пунктов в цену перед вызовами SetStopLoss и SetTakeProfit, тем самым соблюдаются правила форматирования шага цены из исходного кода MQL.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// MACD Divergence RSI strategy: RSI filter + MACD signal line crossover.
/// Buys when RSI below threshold and MACD crosses above signal.
/// Sells when RSI above threshold and MACD crosses below signal.
/// </summary>
public class MacdDivergenceRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevMacd;
	private decimal _prevSignal;
	private decimal _prevRsi;
	private bool _hasPrev;

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

	public MacdDivergenceRsiStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMacd = 0;
		_prevSignal = 0;
		_prevRsi = 0;
		_hasPrev = false;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var macd = new MovingAverageConvergenceDivergenceSignal
		{
			Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
			SignalMa = { Length = 9 }
		};
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.BindEx(macd, rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue rsiValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!macdValue.IsFinal || !rsiValue.IsFinal) return;
		if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
		if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;

		var rsi = rsiValue.ToDecimal();

		if (_hasPrev)
		{
			if (_prevMacd <= _prevSignal && macdMain > signal && rsi < 40 && Position <= 0)
				BuyMarket();
			else if (_prevMacd >= _prevSignal && macdMain < signal && rsi > 60 && Position >= 0)
				SellMarket();
		}

		_prevMacd = macdMain;
		_prevSignal = signal;
		_prevRsi = rsi;
		_hasPrev = true;
	}
}