Ver en GitHub

Supertrend RSI Divergence

The Supertrend RSI Divergence strategy is built around that uses Supertrend indicator along with RSI divergence to identify trading opportunities.

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

Signals trigger when Divergence confirms divergence setups on intraday (15m) data. This makes the method suitable for active traders.

Stops rely on ATR multiples and factors like SupertrendPeriod, SupertrendMultiplier. Adjust these defaults to balance risk and reward.

Details

  • Entry Criteria: see implementation for indicator conditions.
  • Long/Short: Both directions.
  • Exit Criteria: opposite signal or stop logic.
  • Stops: Yes, using indicator-based calculations.
  • Default Values:
    • SupertrendPeriod = 10
    • SupertrendMultiplier = 3.0m
    • RsiPeriod = 14
    • CandleType = TimeSpan.FromMinutes(15).TimeFrame()
  • Filters:
    • Category: Trend following
    • Direction: Both
    • Indicators: Divergence
    • Stops: Yes
    • Complexity: Intermediate
    • Timeframe: Intraday (15m)
    • Seasonality: No
    • Neural Networks: No
    • Divergence: Yes
    • 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 that uses Supertrend indicator along with RSI divergence to identify trading opportunities.
/// </summary>
public class SupertrendRsiDivergenceStrategy : Strategy
{
	private readonly StrategyParam<int> _supertrendPeriod;
	private readonly StrategyParam<decimal> _supertrendMultiplier;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private SuperTrend _supertrend;
	private RelativeStrengthIndex _rsi;

	// Data for divergence detection
	private readonly SynchronizedList<decimal> _prices = [];
	private readonly SynchronizedList<decimal> _rsiValues = [];

	// Supertrend state tracking
	private decimal _supertrendValue;
	private TrendDirections _trendDirection = TrendDirections.None;

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

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

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

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

	/// <summary>
	/// Initializes a new instance of the <see cref="SupertrendRsiDivergenceStrategy"/>.
	/// </summary>
	public SupertrendRsiDivergenceStrategy()
	{
		_supertrendPeriod = Param(nameof(SupertrendPeriod), 10)
		.SetDisplay("Supertrend Period", "Supertrend ATR period", "Supertrend")
		
		.SetOptimize(5, 20, 1);

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

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
		.SetDisplay("RSI Period", "RSI period for divergence detection", "RSI")
		
		.SetOptimize(8, 20, 2);

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

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

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

		_prices.Clear();
		_rsiValues.Clear();
_trendDirection = TrendDirections.None;
		_supertrendValue = 0;
	}

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

		_supertrend = new SuperTrend
		{
			Length = SupertrendPeriod,
			Multiplier = SupertrendMultiplier
		};

		_rsi = new RelativeStrengthIndex
		{
			Length = RsiPeriod
		};

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(_supertrend, _rsi, ProcessCandle)
			.Start();

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

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

	private void ProcessCandle(ICandleMessage candle, decimal supertrendValue, decimal rsiValue)
	{
		// Skip unfinished candles
		if (candle.State != CandleStates.Finished)
		return;


		// Extract values from indicators
		_supertrendValue = supertrendValue;
		decimal rsi = rsiValue;

		// Store values for divergence calculation
		_prices.Add(candle.ClosePrice);
		_rsiValues.Add(rsi);

		// Keep reasonable history
		while (_prices.Count > 50)
		{
			_prices.RemoveAt(0);
			_rsiValues.RemoveAt(0);
		}

		// Determine Supertrend trend direction
TrendDirections previousDirection = _trendDirection;

		if (candle.ClosePrice > _supertrendValue)
_trendDirection = TrendDirections.Up;
		else if (candle.ClosePrice < _supertrendValue)
_trendDirection = TrendDirections.Down;

		// Check for trend direction change
bool trendDirectionChanged = previousDirection != TrendDirections.None && previousDirection != _trendDirection;

		// Check for divergence
		bool bullishDivergence = CheckBullishDivergence();
		bool bearishDivergence = CheckBearishDivergence();

		if (Position != 0)
			return;

		// Bullish setup - price above Supertrend with RSI not overbought
		if (candle.ClosePrice > _supertrendValue && rsi < 60m)
			BuyMarket();
		// Bearish setup - price below Supertrend with RSI not oversold
		else if (candle.ClosePrice < _supertrendValue && rsi > 40m)
			SellMarket();
	}

	private bool CheckBullishDivergence()
	{
		// Need at least a few candles for divergence check
		if (_prices.Count < 5 || _rsiValues.Count < 5)
		return false;

		// Check for bullish divergence: price making lower lows while RSI making higher lows
		// Look at the last 5 candles for a simple check
		decimal currentPrice = _prices[_prices.Count - 1];
		decimal previousPrice = _prices[_prices.Count - 2];

		decimal currentRsi = _rsiValues[_rsiValues.Count - 1];
		decimal previousRsi = _rsiValues[_rsiValues.Count - 2];

		// Bullish divergence: price lower but RSI higher
		bool divergence = currentPrice < previousPrice && currentRsi > previousRsi;

		if (divergence)
		{
			LogInfo($"Bullish Divergence Detected: Price {previousPrice:F2}->{currentPrice:F2}, RSI {previousRsi:F2}->{currentRsi:F2}");
		}

		return divergence;
	}

	private bool CheckBearishDivergence()
	{
		// Need at least a few candles for divergence check
		if (_prices.Count < 5 || _rsiValues.Count < 5)
		return false;

		// Check for bearish divergence: price making higher highs while RSI making lower highs
		// Look at the last 5 candles for a simple check
		decimal currentPrice = _prices[_prices.Count - 1];
		decimal previousPrice = _prices[_prices.Count - 2];

		decimal currentRsi = _rsiValues[_rsiValues.Count - 1];
		decimal previousRsi = _rsiValues[_rsiValues.Count - 2];

		// Bearish divergence: price higher but RSI lower
		bool divergence = currentPrice > previousPrice && currentRsi < previousRsi;

		if (divergence)
		{
			LogInfo($"Bearish Divergence Detected: Price {previousPrice:F2}->{currentPrice:F2}, RSI {previousRsi:F2}->{currentRsi:F2}");
		}

		return divergence;
	}

	// Trend direction enum for tracking Supertrend state
	private enum TrendDirections
	{
		None,
		Up,
		Down
	}
}