Ver en GitHub

Estrategia de Desaceleración RSI

La estrategia de Desaceleración RSI reacciona a lecturas extremas del Índice de Fuerza Relativa que muestran signos de debilitamiento del momentum. Cuando el RSI se aproxima a zonas de sobrecompra o sobreventa y su cambio entre barras cae por debajo de un punto, la estrategia asume que el mercado está listo para una reversión.

Se abre una posición larga cuando el RSI alcanza o supera el nivel superior y el crecimiento del indicador se ralentiza. Se abre una posición corta cuando el RSI cae al nivel inferior con una desaceleración similar. Cualquier posición opuesta existente se cierra antes de entrar en una nueva operación.

La configuración predeterminada utiliza velas de 6 horas y un RSI de 2 períodos con umbrales de 90 y 10. Estos valores imitan la implementación original de MetaTrader.

Detalles

  • Criterios de entrada:
    • Largo: RSI >= LevelMax y |RSI - prev RSI| < 1 (cuando la desaceleración está habilitada)
    • Corto: RSI <= LevelMin y |RSI - prev RSI| < 1 (cuando la desaceleración está habilitada)
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida:
    • Largo: Señal opuesta o entrada corta.
    • Corto: Señal opuesta o entrada larga.
  • Stops: Sin stops automáticos.
  • Valores predeterminados:
    • RsiPeriod = 2
    • LevelMax = 90
    • LevelMin = 10
    • SeekSlowdown = true
    • CandleType = TimeSpan.FromHours(6)
  • Filtros:
    • Categoría: Reversión
    • Dirección: Ambos
    • Indicadores: RSI
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: Intradía a swing
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: Sí (desaceleración)
    • Nivel de riesgo: Medio
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>
/// RSI slowdown strategy.
/// Opens long when RSI reaches the upper level and slows down.
/// Opens short when RSI reaches the lower level and slows down.
/// </summary>
public class RsiSlowdownStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _levelMax;
	private readonly StrategyParam<decimal> _levelMin;
	private readonly StrategyParam<bool> _seekSlowdown;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _previousRsi;

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

	/// <summary>
	/// Upper RSI level.
	/// </summary>
	public decimal LevelMax
	{
		get => _levelMax.Value;
		set => _levelMax.Value = value;
	}

	/// <summary>
	/// Lower RSI level.
	/// </summary>
	public decimal LevelMin
	{
		get => _levelMin.Value;
		set => _levelMin.Value = value;
	}

	/// <summary>
	/// Enable slowdown condition.
	/// </summary>
	public bool SeekSlowdown
	{
		get => _seekSlowdown.Value;
		set => _seekSlowdown.Value = value;
	}

	/// <summary>
	/// The type of candles to use for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Constructor.
	/// </summary>
	public RsiSlowdownStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 2)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI calculation period", "RSI")
			
			.SetOptimize(2, 14, 1);

		_levelMax = Param(nameof(LevelMax), 90m)
			.SetDisplay("Upper Level", "Overbought RSI level", "RSI")
			
			.SetOptimize(50m, 100m, 5m);

		_levelMin = Param(nameof(LevelMin), 10m)
			.SetDisplay("Lower Level", "Oversold RSI level", "RSI")
			
			.SetOptimize(0m, 50m, 5m);

		_seekSlowdown = Param(nameof(SeekSlowdown), true)
			.SetDisplay("Seek Slowdown", "Check RSI change below 1", "RSI");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(6).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles for the strategy", "General");

		_previousRsi = decimal.MinValue;
	}

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

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

		_previousRsi = decimal.MinValue;
	}

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

		_previousRsi = decimal.MinValue;

		var rsi = new RelativeStrengthIndex
		{
			Length = RsiPeriod
		};

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

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

		if (_previousRsi == decimal.MinValue)
		{
			_previousRsi = rsiValue;
			return;
		}

		if (!IsFormedAndOnlineAndAllowTrading())
		{
			_previousRsi = rsiValue;
			return;
		}

		var isSlowdown = !SeekSlowdown || Math.Abs(_previousRsi - rsiValue) < 1m;

		if (isSlowdown)
		{
		if (rsiValue >= LevelMax && Position <= 0)
		{
		BuyMarket();
		}
		else if (rsiValue <= LevelMin && Position >= 0)
		{
		SellMarket();
		}
		}

		_previousRsi = rsiValue;
	}
}