Ver en GitHub

RSI Expert Breakout Strategy

Overview

  • Port of the MetaTrader 5 "RSI_Expert" strategy that trades RSI threshold breakouts.
  • Uses a single RSI indicator to detect momentum reversals near oversold/overbought regions.
  • Implements the original fixed take-profit, stop-loss, and trailing-stop management expressed in pips.

Strategy Logic

  1. Build RSI on the selected candle series (default period: 14).
  2. Track the two most recent completed RSI values.
  3. Go long when RSI rises back above the lower threshold (20 by default) after previously being below it.
  4. Go short when RSI falls back below the upper threshold (60 by default) after previously being above it.
  5. Close any opposite exposure before opening a new position to stay net-flat-to-direction.
  6. Manage open trades with optional stop loss, take profit, and trailing stop distances measured in pips.

Parameters

Name Description Default
CandleType Time frame used for candle aggregation. 1-hour candles
TradeVolume Order size used for entries. 0.1
RsiPeriod RSI lookback length. 14
RsiUpperLevel RSI threshold that signals a bearish reversal. 60
RsiLowerLevel RSI threshold that signals a bullish reversal. 20
TakeProfitPips Take-profit distance in pips (0 disables). 60
StopLossPips Stop-loss distance in pips (0 disables). 0
TrailingStopPips Trailing-stop distance in pips (0 disables trailing). 15
TrailingStepPips Minimum price improvement before trailing stop is shifted again. 5

Pip interpretation: In the StockSharp port a "pip" equals one Security.PriceStep. On FX symbols with fractional quoting ensure the price step matches the instrument's pip convention, otherwise adjust the input distances accordingly.

Risk Management

  • Take profit and stop loss are evaluated on every completed candle using the latest average position price.
  • The trailing stop activates only after the move exceeds TrailingStopPips + TrailingStepPips and then trails the close by TrailingStopPips as price advances.
  • Stop checks use candle highs/lows to emulate intrabar triggers; when triggered the position is closed at market.

Conversion Notes

  • High-level API is used (SubscribeCandles + Bind), and RSI values are consumed directly from the binding callback without manual indicator buffers.
  • Trailing stop logic reproduces the MQL conditions, including the step threshold before each adjustment.
  • The strategy resets trailing state whenever exposure flips or closes to avoid stale levels carrying into a new trade.
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>
/// RSI Expert Breakout strategy. Trades RSI threshold crossovers.
/// </summary>
public class RsiExpertBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpper;
	private readonly StrategyParam<decimal> _rsiLower;

	private decimal? _prevRsi;

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

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

	public decimal RsiUpper
	{
		get => _rsiUpper.Value;
		set => _rsiUpper.Value = value;
	}

	public decimal RsiLower
	{
		get => _rsiLower.Value;
		set => _rsiLower.Value = value;
	}

	public RsiExpertBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe", "General");

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

		_rsiUpper = Param(nameof(RsiUpper), 70m)
			.SetDisplay("RSI Upper", "Overbought threshold", "Indicators");

		_rsiLower = Param(nameof(RsiLower), 30m)
			.SetDisplay("RSI Lower", "Oversold threshold", "Indicators");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = null;
	}

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

		_prevRsi = null;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

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

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_prevRsi = rsiVal;
			return;
		}

		if (_prevRsi == null)
		{
			_prevRsi = rsiVal;
			return;
		}

		// RSI crosses above lower level from below → buy
		if (_prevRsi.Value < RsiLower && rsiVal >= RsiLower && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// RSI crosses below upper level from above → sell
		else if (_prevRsi.Value > RsiUpper && rsiVal <= RsiUpper && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevRsi = rsiVal;
	}
}