Ver no GitHub

Rsi Supertrend Strategy

Strategy based on RSI and Supertrend indicators. Enters long when RSI is oversold (< 30) and price is above Supertrend Enters short when RSI is overbought (> 70) and price is below Supertrend

Testing indicates an average annual return of about 112%. It performs best in the forex market.

The RSI oscillator defines momentum extremes while Supertrend points to the prevailing direction. Trades occur when RSI aligns with the Supertrend color.

Works for traders who appreciate a trailing-stop style exit. ATR settings further safeguard the position.

Details

  • Entry Criteria:
    • Long: RSI < 30 && Close > Supertrend
    • Short: RSI > 70 && Close < Supertrend
  • Long/Short: Both
  • Exit Criteria: Supertrend change
  • Stops: Trailing with Supertrend
  • Default Values:
    • RsiPeriod = 14
    • SupertrendPeriod = 10
    • SupertrendMultiplier = 3.0m
    • CandleType = TimeSpan.FromMinutes(5).TimeFrame()
  • Filters:
    • Category: Mean reversion
    • Direction: Both
    • Indicators: RSI, Supertrend
    • Stops: Yes
    • Complexity: Intermediate
    • Timeframe: Mid-term
    • Seasonality: No
    • Neural Networks: No
    • Divergence: No
    • Risk Level: Medium
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 based on RSI and Supertrend indicators.
/// Enters long when RSI is oversold (< 30) and price is above Supertrend
/// Enters short when RSI is overbought (> 70) and price is below Supertrend
/// </summary>
public class RsiSupertrendStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _supertrendPeriod;
	private readonly StrategyParam<decimal> _supertrendMultiplier;
	private readonly StrategyParam<DataType> _candleType;
	
	// Custom Supertrend indicator
	private AverageTrueRange _atr;
	private decimal _upValue;
	private decimal _downValue;
	private decimal _currentTrend;
	private decimal _prevUpValue;
	private decimal _prevDownValue;
	private decimal _prevClose;
	private bool _isFirstValue = true;

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

	/// <summary>
	/// Supertrend ATR period
	/// </summary>
	public int SupertrendPeriod
	{
		get => _supertrendPeriod.Value;
		set => _supertrendPeriod.Value = value;
	}

	/// <summary>
	/// Supertrend ATR multiplier
	/// </summary>
	public decimal SupertrendMultiplier
	{
		get => _supertrendMultiplier.Value;
		set => _supertrendMultiplier.Value = value;
	}

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

	/// <summary>
	/// Constructor
	/// </summary>
	public RsiSupertrendStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Period for RSI indicator", "Indicators")
			
			.SetOptimize(10, 20, 2);

		_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Supertrend Period", "ATR period for Supertrend", "Indicators")
			
			.SetOptimize(7, 14, 1);

		_supertrendMultiplier = Param(nameof(SupertrendMultiplier), 3.0m)
			.SetGreaterThanZero()
			.SetDisplay("Supertrend Multiplier", "ATR multiplier for Supertrend", "Indicators")
			
			.SetOptimize(2.0m, 4.0m, 0.5m);

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

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

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

		// Reset state variables
		_atr = null;
		_isFirstValue = true;
		_currentTrend = 1;
		_downValue = 0;
		_prevUpValue = 0;
		_prevDownValue = 0;
		_prevClose = 0;
		_upValue = 0;
	}

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

		// Create RSI indicator
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		// Create ATR indicator for Supertrend calculation
		_atr = new AverageTrueRange { Length = SupertrendPeriod };
		
		// Enable using Supertrend as a dynamic stop-loss
		// We'll implement our own stop management based on Supertrend

		// Subscribe to candles and bind indicators
		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(rsi, _atr, ProcessCandle)
			.Start();

		// Setup chart visualization if available
		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			
			// Separate area for RSI
			var rsiArea = CreateChartArea();
			if (rsiArea != null)
			{
				DrawIndicator(rsiArea, rsi);
			}
			
			// Note: We'll manually draw Supertrend lines in ProcessCandle method
			
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsiValue, decimal atrValue)
	{
		// Skip unfinished candles
		if (candle.State != CandleStates.Finished)
			return;
		
		// Check if strategy is ready to trade
		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		// Calculate Supertrend
		var closePrice = candle.ClosePrice;
		var highPrice = candle.HighPrice;
		var lowPrice = candle.LowPrice;
		
		// Basic bands calculation
		var basicUpperBand = (highPrice + lowPrice) / 2 + SupertrendMultiplier * atrValue;
		var basicLowerBand = (highPrice + lowPrice) / 2 - SupertrendMultiplier * atrValue;
		
		if (_isFirstValue)
		{
			// Initialize values for the first candle
			_upValue = basicUpperBand;
			_downValue = basicLowerBand;
			_prevUpValue = _upValue;
			_prevDownValue = _downValue;
			_prevClose = closePrice;
			_isFirstValue = false;
			return;
		}
		
		// Calculate final upper and lower bands
		_upValue = basicUpperBand;
		if (_upValue < _prevUpValue || _prevClose > _prevUpValue)
			_upValue = _prevUpValue;
		
		_downValue = basicLowerBand;
		if (_downValue > _prevDownValue || _prevClose < _prevDownValue)
			_downValue = _prevDownValue;
		
		// Determine trend direction
		var prevTrend = _currentTrend;
		
		if (_prevClose <= _prevUpValue)
			_currentTrend = -1; // Downtrend
		
		if (_prevClose >= _prevDownValue)
			_currentTrend = 1; // Uptrend
		
		// Store values for next iteration
		_prevUpValue = _upValue;
		_prevDownValue = _downValue;
		_prevClose = closePrice;
		
		// Get Supertrend value based on current trend
		var supertrendValue = _currentTrend == 1 ? _downValue : _upValue;
		
		// Trading logic
		var isTrendChange = prevTrend != _currentTrend;
		
		// Long condition: RSI oversold and price above Supertrend
		if (rsiValue < 30 && _currentTrend == 1 && Position <= 0)
		{
			BuyMarket(Volume + Math.Abs(Position));
			
			// Note: We're using Supertrend as our stop-loss level,
			// so we don't need to set a separate stop-loss order
		}
		// Short condition: RSI overbought and price below Supertrend
		else if (rsiValue > 70 && _currentTrend == -1 && Position >= 0)
		{
			SellMarket(Volume + Math.Abs(Position));
		}
		// Exit conditions - based on Supertrend direction change
		else if (isTrendChange)
		{
			if (_currentTrend == -1 && Position > 0)
			{
				// Trend changed to down - exit long
				SellMarket(Position);
			}
			else if (_currentTrend == 1 && Position < 0)
			{
				// Trend changed to up - exit short
				BuyMarket(Math.Abs(Position));
			}
		}
	}
}