Ver en GitHub

Estrategia de Tendencia RSI MA

Esta estrategia combina el Índice de Fuerza Relativa (RSI) con un filtro de tendencia de media móvil. Se abre una posición larga cuando el RSI cae por debajo de un nivel de compra especificado mientras la media móvil rápida está por encima de la media móvil lenta. Se abre una posición corta cuando el RSI sube por encima de un nivel de venta especificado mientras la media móvil rápida está por debajo de la media móvil lenta.

Parámetros

  • RSI Period – longitud del indicador RSI.
  • RSI Buy Level – valor de RSI por debajo del cual se abre una posición larga.
  • RSI Sell Level – valor de RSI por encima del cual se abre una posición corta.
  • Fast MA Period – período de la media móvil rápida.
  • Slow MA Period – período de la media móvil lenta.
  • Candle Type – serie de velas utilizada para los cálculos.

Lógica

  1. Suscribirse a la serie de velas seleccionada.
  2. Calcular RSI, MA rápida y MA lenta para cada vela finalizada.
  3. Detectar tendencia alcista cuando la MA rápida está por encima de la MA lenta y tendencia bajista cuando está por debajo.
  4. Entrar largo cuando RSI < nivel de compra y la tendencia es alcista, cerrando posiciones cortas si las hay.
  5. Entrar corto cuando RSI > nivel de venta y la tendencia es bajista, cerrando posiciones largas si las hay.

Notas

  • La estrategia utiliza órdenes de mercado para las entradas.
  • Las señales de operación se procesan solo en velas finalizadas.
  • Los parámetros están disponibles para optimización en la interfaz de usuario.
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 combining RSI with moving average trend filter.
/// Buys when RSI is below the buy level and fast MA is above slow MA.
/// Sells when RSI is above the sell level and fast MA is below slow MA.
/// </summary>
public class RsiMaTrendStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiBuyLevel;
	private readonly StrategyParam<decimal> _rsiSellLevel;
	private readonly StrategyParam<int> _fastMaPeriod;
	private readonly StrategyParam<int> _slowMaPeriod;
	private readonly StrategyParam<DataType> _candleType;

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

	/// <summary>
	/// RSI level to trigger buy.
	/// </summary>
	public decimal RsiBuyLevel
	{
		get => _rsiBuyLevel.Value;
		set => _rsiBuyLevel.Value = value;
	}

	/// <summary>
	/// RSI level to trigger sell.
	/// </summary>
	public decimal RsiSellLevel
	{
		get => _rsiSellLevel.Value;
		set => _rsiSellLevel.Value = value;
	}

	/// <summary>
	/// Fast moving average period.
	/// </summary>
	public int FastMaPeriod
	{
		get => _fastMaPeriod.Value;
		set => _fastMaPeriod.Value = value;
	}

	/// <summary>
	/// Slow moving average period.
	/// </summary>
	public int SlowMaPeriod
	{
		get => _slowMaPeriod.Value;
		set => _slowMaPeriod.Value = value;
	}

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

	/// <summary>
	/// Constructor.
	/// </summary>
	public RsiMaTrendStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Length of RSI indicator", "Indicators")
			
			.SetOptimize(10, 30, 5);

		_rsiBuyLevel = Param(nameof(RsiBuyLevel), 45m)
			.SetDisplay("RSI Buy Level", "Value below which long is opened", "Indicators")
			
			.SetOptimize(20m, 40m, 5m);

		_rsiSellLevel = Param(nameof(RsiSellLevel), 55m)
			.SetDisplay("RSI Sell Level", "Value above which short is opened", "Indicators")
			
			.SetOptimize(60m, 80m, 5m);

		_fastMaPeriod = Param(nameof(FastMaPeriod), 10)
			.SetGreaterThanZero()
			.SetDisplay("Fast MA Period", "Length of fast moving average", "Indicators")
			
			.SetOptimize(20, 80, 10);

		_slowMaPeriod = Param(nameof(SlowMaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("Slow MA Period", "Length of slow moving average", "Indicators")
			
			.SetOptimize(100, 300, 20);

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles", "General");
	}

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

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

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var fastMa = new ExponentialMovingAverage { Length = FastMaPeriod };
		var slowMa = new ExponentialMovingAverage { Length = SlowMaPeriod };

		var subscription = SubscribeCandles(CandleType);

		subscription
			.Bind(rsi, fastMa, slowMa, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var isUpTrend = fastMaValue > slowMaValue;

		if (rsiValue < RsiBuyLevel && isUpTrend && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		else if (rsiValue > RsiSellLevel && !isUpTrend && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
	}
}