Открыть на GitHub

Стратегия MACD Diver and RSI

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

Стратегия является портом MetaTrader 5 советника «Macd diver and rsi» на платформу StockSharp. Сохранена исходная двухэтапная логика сигналов: RSI определяет области перекупленности или перепроданности, а гистограмма MACD подтверждает разворот импульса. Длинные и короткие сигналы настраиваются раздельно, что позволяет тонко адаптировать поведение под направление тренда.

Работа ведётся по одному потоку свечей (таймфрейм задаётся параметром). Сделки открываются рыночными заявками по инструменту стратегии. Обработка индикаторов выполнена через высокоуровневый API BindEx в соответствии с требованиями репозитория.

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

  1. Подготовка индикаторов
    • Создаются два экземпляра RSI — для длинных и коротких сценариев с собственными периодами и порогами.
    • Создаются два индикатора MovingAverageConvergenceDivergenceSignal, повторяющие настройки MACD для лонгов и шортов. Для подтверждения используется компонент гистограммы.
  2. Условия входа
    • Лонг: если значение «длинного» RSI меньше либо равно порогу перепроданности и гистограмма MACD переходит из отрицательной зоны в положительную, открывается покупка. При наличии короткой позиции она закрывается и разворот выполняется той же заявкой.
    • Шорт: если значение «короткого» RSI больше либо равно порогу перекупленности и гистограмма MACD переходит из положительной зоны в отрицательную, открывается продажа. Активный лонг сначала закрывается.
  3. Управление риском
    • После входа запоминается цена закрытия сигнальной свечи.
    • Уровни стоп-лосса и тейк-профита рассчитываются от этой цены по заданным значениям в пунктах для каждого направления.
    • Пересчёт пунктов выполняется через PriceStep инструмента; для инструментов с 3 или 5 знаками после запятой шаг умножается на 10, что соответствует привычной для MT5 трактовке «пункта».
    • На каждой завершённой свече проверяется, достигнут ли стоп или тейк. При пробое позиция закрывается рыночной заявкой.
  4. Сопровождение позиции
    • Состояние позиции очищается, когда объём становится нулевым (по стопу/тейку или при развороте).
    • Дополнительное сопровождение (частичные фиксации, трейлинг) не используется — только фиксированные уровни.

Параметры

  • CandleType — таймфрейм свечей, по которым строятся сигналы.
  • LongRsiPeriod / ShortRsiPeriod — периоды RSI для длинных и коротких сценариев.
  • LongRsiThreshold / ShortRsiThreshold — пороги RSI, разрешающие вход (перепроданность для лонга, перекупленность для шорта).
  • LongMacdFastLength, LongMacdSlowLength, LongMacdSignalLength — периоды EMA в MACD для длинной стороны.
  • ShortMacdFastLength, ShortMacdSlowLength, ShortMacdSignalLength — параметры MACD для короткой стороны.
  • LongVolume, ShortVolume — объём сделки. При развороте к объёму добавляется абсолютная величина текущей позиции, чтобы одной заявкой закрыть старую и открыть новую.
  • LongStopLossPips, LongTakeProfitPips, ShortStopLossPips, ShortTakeProfitPips — расстояния до стоп-лосса и тейк-профита в пунктах (0 отключает уровень).

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

  • Для корректной работы нужен ненулевой PriceStep. При отсутствии шага используется запасное значение 0.0001, чтобы избежать деления на ноль.
  • Раздельные индикаторы для лонга и шорта позволяют использовать асимметричную фильтрацию — например, ужесточить условия для шорта и оставить лонг более чувствительным.
  • В код добавлены комментарии на английском языке, разъясняющие этапы работы стратегии и соответствующие требованиям проекта.
namespace StockSharp.Samples.Strategies;

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

/// <summary>
/// MACD Diver And RSI strategy: RSI extremes + MACD histogram crossover.
/// Buys when RSI below 30 and MACD histogram crosses above zero.
/// Sells when RSI above 70 and MACD histogram crosses below zero.
/// </summary>
public class MacdDiverAndRsiStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;

	private decimal _prevHistogram;
	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 MacdDiverAndRsiStrategy()
	{
		_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();
		_prevHistogram = 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 histogram = macdMain - signal;
		var rsi = rsiValue.ToDecimal();

		if (_hasPrev)
		{
			if (_prevHistogram <= 0 && histogram > 0 && _prevRsi < 35 && Position <= 0)
				BuyMarket();
			else if (_prevHistogram >= 0 && histogram < 0 && _prevRsi > 65 && Position >= 0)
				SellMarket();
		}

		_prevHistogram = histogram;
		_prevRsi = rsi;
		_hasPrev = true;
	}
}