Ver en GitHub

Estrategia RSI Bollinger Bands

Estrategia que combina el Índice de Fuerza Relativa (RSI) con las Bollinger Bands. Se abre una posición larga cuando el RSI está por debajo del umbral de sobreventa y el precio de cierre está por debajo de la banda inferior de Bollinger. Se abre una posición corta cuando el RSI está por encima del umbral de sobrecompra y el precio de cierre está por encima de la banda superior de Bollinger. Las posiciones se revierten ante señales opuestas.

Detalles

  • Criterios de entrada: RSI por debajo de RsiOversold y precio de cierre por debajo de la banda inferior para comprar; RSI por encima de RsiOverbought y precio de cierre por encima de la banda superior para vender.
  • Largo/Corto: Ambas direcciones.
  • Criterios de salida: Señal inversa.
  • Stops: Ninguno.
  • Valores predeterminados:
    • CandleType = TimeSpan.FromMinutes(15)
    • RsiPeriod = 20
    • BollingerPeriod = 20
    • BollingerWidth = 2
    • RsiOversold = 30
    • RsiOverbought = 70
  • Filtros:
    • Categoría: Oscilador
    • Dirección: Ambos
    • Indicadores: RSI, Bollinger Bands
    • Stops: No
    • Complejidad: Básico
    • Marco temporal: 15 minutos
    • Estacionalidad: No
    • Redes neuronales: No
    • Divergencia: No
    • 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>
/// RSI combined with Bollinger Bands strategy.
/// Buys when RSI is oversold and price is below the lower band.
/// Sells when RSI is overbought and price is above the upper band.
/// </summary>
public class RsiBollingerBandsStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _bollingerPeriod;
	private readonly StrategyParam<decimal> _bollingerWidth;
	private readonly StrategyParam<decimal> _rsiOversold;
	private readonly StrategyParam<decimal> _rsiOverbought;

	public RsiBollingerBandsStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Primary timeframe", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 14)
			.SetDisplay("RSI Period", "RSI calculation length", "Indicators");

		_bollingerPeriod = Param(nameof(BollingerPeriod), 20)
			.SetDisplay("Bollinger Period", "Bollinger bands length", "Indicators");

		_bollingerWidth = Param(nameof(BollingerWidth), 2m)
			.SetDisplay("Bollinger Width", "Band width multiplier", "Indicators");

		_rsiOversold = Param(nameof(RsiOversold), 35m)
			.SetDisplay("RSI Oversold", "Buy threshold", "Indicators");

		_rsiOverbought = Param(nameof(RsiOverbought), 65m)
			.SetDisplay("RSI Overbought", "Sell threshold", "Indicators");
	}

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public int BollingerPeriod { get => _bollingerPeriod.Value; set => _bollingerPeriod.Value = value; }
	public decimal BollingerWidth { get => _bollingerWidth.Value; set => _bollingerWidth.Value = value; }
	public decimal RsiOversold { get => _rsiOversold.Value; set => _rsiOversold.Value = value; }
	public decimal RsiOverbought { get => _rsiOverbought.Value; set => _rsiOverbought.Value = value; }

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(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 bollinger = new BollingerBands { Length = BollingerPeriod, Width = BollingerWidth };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(rsi, bollinger, ProcessCandle)
			.Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var rsi = rsiValue.IsFormed ? rsiValue.GetValue<decimal>() : (decimal?)null;
		var bb = bbValue as BollingerBandsValue;

		if (rsi is null || bb?.UpBand is not decimal upper || bb?.LowBand is not decimal lower)
			return;

		var buySignal = rsi < RsiOversold && candle.ClosePrice < lower;
		var sellSignal = rsi > RsiOverbought && candle.ClosePrice > upper;

		if (buySignal && Position <= 0)
			BuyMarket();
		else if (sellSignal && Position >= 0)
			SellMarket();
	}
}