Ver en GitHub

Estrategia de Supertrend RSI Divergence

La estrategia Supertrend RSI Divergence utiliza el indicador Supertrend junto con la divergencia RSI para identificar oportunidades de trading.

Las pruebas indican un rendimiento anual promedio de aproximadamente el 67%. Funciona mejor en el mercado de acciones.

Las señales se activan cuando Divergence confirma configuraciones de divergencia en datos intradía (15m). Este método es adecuado para operadores activos.

Los stops se basan en múltiplos de ATR y factores como SupertrendPeriod, SupertrendMultiplier. Ajuste estos valores predeterminados para equilibrar el riesgo y la recompensa.

Detalles

  • Criterios de entrada: ver implementación para condiciones de indicadores.
  • Largo/Corto: Ambos direcciones.
  • Criterios de salida: señal opuesta o lógica de stop.
  • Stops: Sí, usando cálculos basados en indicadores.
  • Valores predeterminados:
    • SupertrendPeriod = 10
    • SupertrendMultiplier = 3.0m
    • RsiPeriod = 14
    • CandleType = TimeSpan.FromMinutes(15).TimeFrame()
  • Filtros:
    • Categoría: Seguimiento de tendencia
    • Dirección: Ambos
    • Indicadores: Divergence
    • Stops: Sí
    • Complejidad: Intermedio
    • Marco temporal: Intradía (15m)
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: Sí
    • Nivel de riesgo: Medio
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
	}
}