Открыть на GitHub

Стратегия XRSI DeMarker Histogram

Краткое описание

Стратегия повторяет логику советника Exp_XRSIDeMarker_Histogram. Торговые решения принимаются по разворотам пользовательского осциллятора, который объединяет RSI и DeMarker и затем сглаживает результат. Можно независимо разрешать или запрещать входы в лонг и шорт, предусмотрены необязательные защитные стопы в шагах цены.

Построение индикатора

  1. Выбор цены – RSI вычисляется по выбранному типу цены (close, open, high, low, median, typical или weighted) с указанным периодом.
  2. Компонент DeMarker – для каждой завершённой свечи определяются величины deMax и deMin:
    • deMax = max(High_t - High_{t-1}, 0)
    • deMin = max(Low_{t-1} - Low_t, 0) Обе последовательности сглаживаются простым скользящим средним с длиной, равной периоду RSI.
    • DeMarker = deMaxAvg / (deMaxAvg + deMinAvg); значение масштабируется в диапазон 0–100.
  3. Сводный осциллятор – итоговое значение вычисляется как (RSI + 100 * DeMarker) / 2.
  4. Сглаживание – сводный осциллятор пропускается через выбранное среднее (SMA, EMA, SMMA, LWMA или Jurik). Если выбран режим, отсутствующий в StockSharp (ParMA, T3, VIDYA, AMA), используется EMA с заданной длиной. Для Jurik учитывается параметр фазы.
  5. История сигналов – значения сохраняются, и условия проверяются на свече сдвига SignalBar, что повторяет оригинальный эксперт, ожидавший открытие новой свечи.

Торговые правила

  • Бычий разворот
    • Условие: значение на SignalBar+1 ниже, чем на SignalBar+2 (нисходящий уклон), и значение на SignalBar разворачивается вверх (>=).
    • Действия:
      • Закрыть текущие шорты, если CloseShortOnLongSignal = true.
      • Открыть лонг объёмом TradeVolume (с учётом разворота из шорта) при включённом AllowBuyEntries.
  • Медвежий разворот
    • Условие: значение на SignalBar+1 выше, чем на SignalBar+2 (восходящий уклон), и значение на SignalBar разворачивается вниз (<=).
    • Действия:
      • Закрыть лонги при CloseLongOnShortSignal = true.
      • Открыть шорт при активном AllowSellEntries.
  • Сигналы игнорируются, пока компоненты индикатора не сформированы, и сделки выполняются только после проверки IsFormedAndOnlineAndAllowTrading().

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

  • Параметры StopLossTicks и TakeProfitTicks задают расстояние в шагах цены. Стратегия умножает значение на Security.PriceStep (при неизвестном шаге используется 1) и закрывает позицию, если внутри свечи достигнут нужный диапазон.
  • Значение 0 отключает соответствующую защиту.
  • TradeVolume задаёт базовый размер заявки и используется при развороте позиции: сначала закрывается противоположная позиция, затем добавляется новый объём.

Параметры

Параметр Описание Значение по умолчанию
TradeVolume Объём новой позиции. 0.1
StopLossTicks Стоп-лосс в шагах цены. 1000
TakeProfitTicks Тейк-профит в шагах цены. 2000
AllowBuyEntries Разрешить входы в лонг. true
AllowSellEntries Разрешить входы в шорт. true
CloseLongOnShortSignal Закрывать лонги при шорт-сигнале. true
CloseShortOnLongSignal Закрывать шорты при лонг-сигнале. true
CandleType Таймфрейм (по умолчанию H4). H4
IndicatorPeriod Период RSI и DeMarker. 14
AppliedPriceSelection Тип цены для RSI. Close
SmoothingMethodSelection Метод сглаживания (SMA/EMA/SMMA/LWMA/Jurik/Adaptive). Sma
SmoothingLength Длина сглаживающего среднего. 5
SmoothingPhase Фаза для Jurik. 15
SignalBar Сдвиг по закрытым свечам для оценки сигнала. 1

Отличия от оригинального эксперта

  • Режимы мани-менеджмента MQL (баланс, свободная маржа и т.п.) заменены на прямой параметр TradeVolume.
  • Параметр Deviation не используется, так как заявки выставляются по рынку.
  • Продвинутые методы сглаживания (ParMA, T3, VIDYA, AMA) недоступны и заменены на EMA через режим Adaptive.
  • Все комментарии в исходном коде написаны на английском языке; обработка свечей выполняется только после их закрытия, как и в исходном советнике.
namespace StockSharp.Samples.Strategies;

using System;

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

/// <summary>
/// XRSI DeMarker Histogram strategy (simplified).
/// Uses RSI combined with momentum to detect reversals.
/// Buys on RSI reversal from oversold, sells on reversal from overbought.
/// </summary>
public class XrsidDeMarkerHistogramStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _smaPeriod;

	private decimal _prevRsi;
	private decimal _prevPrevRsi;
	private bool _initialized;

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

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

	public int SmaPeriod
	{
		get => _smaPeriod.Value;
		set => _smaPeriod.Value = value;
	}

	public XrsidDeMarkerHistogramStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Source candles", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI indicator period", "Indicators");

		_smaPeriod = Param(nameof(SmaPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("SMA Period", "Smoothing period", "Indicators");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = 0m;
		_prevPrevRsi = 0m;
		_initialized = false;
	}

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

		_prevRsi = 0;
		_prevPrevRsi = 0;
		_initialized = false;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var sma = new SimpleMovingAverage { Length = SmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, sma, (ICandleMessage candle, decimal rsiValue, decimal smaValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!_initialized)
				{
					_prevPrevRsi = rsiValue;
					_prevRsi = rsiValue;
					_initialized = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					_prevPrevRsi = _prevRsi;
					_prevRsi = rsiValue;
					return;
				}

				// Buy on RSI reversal from oversold (V-bottom)
				var buySignal = _prevPrevRsi > _prevRsi && rsiValue >= _prevRsi && _prevRsi < 35m;
				// Sell on RSI reversal from overbought (inverse V)
				var sellSignal = _prevPrevRsi < _prevRsi && rsiValue <= _prevRsi && _prevRsi > 65m;

				if (buySignal && Position <= 0)
				{
					BuyMarket();
				}
				else if (sellSignal && Position >= 0)
				{
					SellMarket();
				}

				_prevPrevRsi = _prevRsi;
				_prevRsi = rsiValue;
			})
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, rsi);
			DrawIndicator(area, sma);
			DrawOwnTrades(area);
		}
	}
}