Ver no GitHub

DT RSI EXP1 Strategy

This port replicates the MT4 expert advisor DT-RSI-EXP1. The strategy scans 15-minute RSI swings to detect double-tops or double-bottoms around the 60/40 levels. A long trade is taken when the recent RSI peaks pull back without printing any troughs below 40, while the 4-hour trend filter points down. Shorts mirror the logic with troughs above 60 and a rising trend filter. A fixed stop-loss and take-profit are attached to every position, and an optional trailing stop protects profits. Positions are force-closed when RSI stretches to extreme 70/30 levels, copying the original exit behaviour.

Details

  • Entry Criteria:
    • Long: two bullish RSI peaks with the second above 60, no bearish troughs below 40 in between, 4-hour EMA below the previous close, RSI(1) crossing above the projected neckline, RSI(2) still below it, RSI(2) < 50 and RSI(0) < 55.
    • Short: two bearish RSI troughs with the second below 40, no bullish peaks above 60 in between, 4-hour EMA above the previous close, RSI(1) crossing below the projected neckline, RSI(2) > 50 and RSI(0) > 47.
  • Long/Short: Both directions.
  • Exit Criteria:
    • RSI extremes (RSI > 70 for longs, RSI < 30 for shorts).
    • Stop-loss / take-profit targets computed from price steps.
    • Optional trailing stop that locks profits once price moves by TrailingStopPoints.
  • Stops: Fixed stop-loss and take-profit, optional trailing stop.
  • Default Values:
    • CandleType = 15-minute candles.
    • TrendCandleType = 240-minute candles (trend filter EMA).
    • RsiPeriod = 47.
    • StopLossPoints = 26.
    • TakeProfitPoints = 76.
    • TrailingStopPoints = 0 (disabled).
  • Filters:
    • Category: Trend-Following Entries on RSI Structures.
    • Direction: Both.
    • Indicators: RSI, EMA trend filter.
    • Stops: Yes.
    • Complexity: Intermediate (multi-constraint swing detection).
    • Timeframe: Intraday (M15 with H4 filter).
    • Seasonality: No.
    • Neural Networks: No.
    • Divergence: No.
    • Risk Level: Medium.

Parameters

Name Default Description Optimizable
CandleType 15-minute Primary candle series used to compute RSI and signals. Yes
TrendCandleType 240-minute Higher timeframe used by the EMA trend filter (replacement for the MT4 RFTL indicator). Yes
RsiPeriod 47 RSI length applied to the primary candles. Yes
StopLossPoints 26 Distance to the stop-loss in price steps. Yes
TakeProfitPoints 76 Distance to the take-profit in price steps. Yes
TrailingStopPoints 0 Trailing-stop offset in price steps (0 disables trailing). Yes

Notes

  • The MetaTrader RFTL custom indicator is approximated with a 10-period EMA on the 240-minute timeframe. Adjust the higher timeframe or EMA length to better match the original environment.
  • Ensure the instrument's PriceStep and StepPrice are configured so that point-based stops align with the broker's tick size.
  • The trailing stop only activates once price advances by more than TrailingStopPoints from the entry price and never loosens beyond the original stop.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// DT RSI EXP1 strategy - RSI overbought/oversold with EMA trend filter.
/// Buys when RSI crosses above oversold level while above EMA trend.
/// Sells when RSI crosses below overbought level while below EMA trend.
/// </summary>
public class DtRsiExp1Strategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<decimal> _oversold;
	private readonly StrategyParam<decimal> _overbought;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public decimal Oversold { get => _oversold.Value; set => _oversold.Value = value; }
	public decimal Overbought { get => _overbought.Value; set => _overbought.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public DtRsiExp1Strategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI period", "Indicators");

		_emaPeriod = Param(nameof(EmaPeriod), 20)
			.SetDisplay("EMA Period", "EMA trend filter period", "Indicators");

		_oversold = Param(nameof(Oversold), 30m)
			.SetDisplay("Oversold", "RSI oversold level", "Indicators");

		_overbought = Param(nameof(Overbought), 70m)
			.SetDisplay("Overbought", "RSI overbought level", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); _prevRsi = 0m; _hasPrev = false; }

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_hasPrev = false;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ema = new ExponentialMovingAverage { Length = EmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, ema, ProcessCandle)
			.Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsi, decimal ema)
	{
		if (candle.State != CandleStates.Finished)
			return;

		var close = candle.ClosePrice;

		if (!_hasPrev)
		{
			_prevRsi = rsi;
			_hasPrev = true;
			return;
		}

		// RSI crosses above oversold + bullish trend
		if (_prevRsi <= Oversold && rsi > Oversold && close > ema && Position == 0)
		{
			BuyMarket();
		}
		// RSI crosses below overbought + bearish trend
		else if (_prevRsi >= Overbought && rsi < Overbought && close < ema && Position == 0)
		{
			SellMarket();
		}

		_prevRsi = rsi;
	}
}