View on GitHub

RSI Stochastic MA Strategy

This strategy combines a simple moving average (SMA) trend filter with RSI and Stochastic oscillators. The moving average defines the market bias. When price is above the SMA the strategy looks for long entries; when below the SMA it seeks short entries. RSI and Stochastic levels identify oversold or overbought conditions to time entries.

Positions are closed when the oscillators leave their extreme zones. This keeps trades aligned with the prevailing trend while avoiding extended moves against the indicators.

Parameters

  • RsiPeriod – RSI calculation period.
  • RsiUpperLevel – RSI overbought threshold.
  • RsiLowerLevel – RSI oversold threshold.
  • MaPeriod – period of the trend moving average.
  • StochKPeriod – %K period for the Stochastic oscillator.
  • StochDPeriod – %D smoothing period for the Stochastic oscillator.
  • StochUpperLevel – Stochastic overbought level.
  • StochLowerLevel – Stochastic oversold level.
  • Volume – order volume.
  • CandleType – candle data type used for calculations.

Indicators

  • Simple Moving Average
  • Relative Strength Index
  • Stochastic Oscillator

Trading rules

  • Buy when price is above the SMA, RSI is below RsiLowerLevel, and both Stochastic lines are below StochLowerLevel.
  • Sell when price is below the SMA, RSI is above RsiUpperLevel, and both Stochastic lines are above StochUpperLevel.
  • Exit long when RSI or Stochastic rises above their upper levels.
  • Exit short when RSI or Stochastic falls below their lower levels.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Combined RSI, Stochastic, and Moving Average strategy.
/// The MA defines the trend. Entries on RSI+Stochastic oversold/overbought in trend direction.
/// </summary>
public class RsiStochasticMaStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpperLevel;
	private readonly StrategyParam<decimal> _rsiLowerLevel;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<decimal> _stochUpperLevel;
	private readonly StrategyParam<decimal> _stochLowerLevel;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<decimal> _takeProfitPct;
	private readonly StrategyParam<DataType> _candleType;

	private StochasticOscillator _stochastic;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal RsiUpperLevel { get => _rsiUpperLevel.Value; set => _rsiUpperLevel.Value = value; }
	public decimal RsiLowerLevel { get => _rsiLowerLevel.Value; set => _rsiLowerLevel.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public decimal StochUpperLevel { get => _stochUpperLevel.Value; set => _stochUpperLevel.Value = value; }
	public decimal StochLowerLevel { get => _stochLowerLevel.Value; set => _stochLowerLevel.Value = value; }
	public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
	public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public RsiStochasticMaStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 3)
			.SetDisplay("RSI Period", "RSI calculation period", "RSI");

		_rsiUpperLevel = Param(nameof(RsiUpperLevel), 65m)
			.SetDisplay("RSI Upper Level", "RSI overbought level", "RSI");

		_rsiLowerLevel = Param(nameof(RsiLowerLevel), 35m)
			.SetDisplay("RSI Lower Level", "RSI oversold level", "RSI");

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetDisplay("MA Period", "Moving average period", "Trend");

		_stochUpperLevel = Param(nameof(StochUpperLevel), 60m)
			.SetDisplay("Stochastic Upper", "Stochastic overbought level", "Stochastic");

		_stochLowerLevel = Param(nameof(StochLowerLevel), 40m)
			.SetDisplay("Stochastic Lower", "Stochastic oversold level", "Stochastic");

		_stopLossPct = Param(nameof(StopLossPct), 2m)
			.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

		_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
			.SetDisplay("Take Profit %", "Take profit percentage", "Risk");

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

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

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

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ma = new ExponentialMovingAverage { Length = MaPeriod };
		_stochastic = new StochasticOscillator();

		Indicators.Add(_stochastic);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ma, rsi, (candle, maValue, rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				var stochResult = _stochastic.Process(candle);
				if (!_stochastic.IsFormed)
					return;

				var stochVal = (StochasticOscillatorValue)stochResult;
				if (stochVal.K is not decimal k || stochVal.D is not decimal d)
					return;

				var price = candle.ClosePrice;
				var isUpTrend = price > maValue;
				var isDownTrend = price < maValue;

				if (isUpTrend && rsiValue < RsiLowerLevel && k < StochLowerLevel && Position == 0)
				{
					BuyMarket();
				}
				else if (isDownTrend && rsiValue > RsiUpperLevel && k > StochUpperLevel && Position == 0)
				{
					SellMarket();
				}
			})
			.Start();

		StartProtection(
			takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
			stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
			useMarketOrders: true);

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