Ver no GitHub

RSI MA Trend Strategy

This strategy combines the Relative Strength Index (RSI) with a moving average trend filter. A long position is opened when the RSI drops below a specified buy level while the fast moving average is above the slow moving average. A short position is opened when the RSI rises above a specified sell level while the fast moving average is below the slow moving average.

Parameters

  • RSI Period – length of the RSI indicator.
  • RSI Buy Level – RSI value below which a long position is opened.
  • RSI Sell Level – RSI value above which a short position is opened.
  • Fast MA Period – period of the fast moving average.
  • Slow MA Period – period of the slow moving average.
  • Candle Type – candle series used for calculations.

Logic

  1. Subscribe to the selected candle series.
  2. Calculate RSI, fast MA, and slow MA for each finished candle.
  3. Detect uptrend when fast MA is above slow MA and downtrend when it is below.
  4. Enter long when RSI < buy level and trend is up, closing short positions if any.
  5. Enter short when RSI > sell level and trend is down, closing long positions if any.

Notes

  • The strategy uses market orders for entries.
  • Trade signals are processed only on finished candles.
  • Parameters are exposed for optimization in the user interface.
using System;
using System.Linq;
using System.Collections.Generic;

using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Strategy combining RSI with moving average trend filter.
/// Buys when RSI is below the buy level and fast MA is above slow MA.
/// Sells when RSI is above the sell level and fast MA is below slow MA.
/// </summary>
public class RsiMaTrendStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiBuyLevel;
	private readonly StrategyParam<decimal> _rsiSellLevel;
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	/// <summary>
	/// RSI period length.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}

	/// <summary>
	/// RSI level to trigger buy.
	/// </summary>
	public decimal RsiBuyLevel
	{
		get => _rsiBuyLevel.Value;
		set => _rsiBuyLevel.Value = value;
	}

	/// <summary>
	/// RSI level to trigger sell.
	/// </summary>
	public decimal RsiSellLevel
	{
		get => _rsiSellLevel.Value;
		set => _rsiSellLevel.Value = value;
	}

	/// <summary>
	/// Fast moving average period.
	/// </summary>
	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	/// <summary>
	/// Slow moving average period.
	/// </summary>
	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

	/// <summary>
	/// Candle type used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public RsiMaTrendStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Length of RSI indicator", "Indicators")
			
			.SetOptimize(10, 30, 5);

		_rsiBuyLevel = Param(nameof(RsiBuyLevel), 45m)
			.SetDisplay("RSI Buy Level", "Value below which long is opened", "Indicators")
			
			.SetOptimize(20m, 40m, 5m);

		_rsiSellLevel = Param(nameof(RsiSellLevel), 55m)
			.SetDisplay("RSI Sell Level", "Value above which short is opened", "Indicators")
			
			.SetOptimize(60m, 80m, 5m);

		_fastMaPeriod = Param(nameof(FastMaPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
			
			.SetOptimize(20, 80, 10);

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
			
			.SetOptimize(100, 300, 20);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

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

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(rsi, fastMa, slowMa, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var isUpTrend = fastMaValue > slowMaValue;

		if (rsiValue < RsiBuyLevel && isUpTrend && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (rsiValue > RsiSellLevel && !isUpTrend && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}