Ver en GitHub

Estrategia RSI Stochastic MA

Esta estrategia combina un filtro de tendencia de media móvil simple (SMA) con los osciladores RSI y Stochastic. La media móvil define la tendencia del mercado. Cuando el precio está por encima de la SMA, la estrategia busca entradas largas; cuando está por debajo de la SMA, busca entradas cortas. Los niveles de RSI y Stochastic identifican condiciones de sobreventa o sobrecompra para sincronizar las entradas.

Las posiciones se cierran cuando los osciladores abandonan sus zonas extremas. Esto mantiene las operaciones alineadas con la tendencia predominante evitando movimientos prolongados contra los indicadores.

Parámetros

  • RsiPeriod – período de cálculo del RSI.
  • RsiUpperLevel – umbral de sobrecompra del RSI.
  • RsiLowerLevel – umbral de sobreventa del RSI.
  • MaPeriod – período de la media móvil de tendencia.
  • StochKPeriod – período %K del oscilador Stochastic.
  • StochDPeriod – período de suavizado %D del oscilador Stochastic.
  • StochUpperLevel – nivel de sobrecompra del Stochastic.
  • StochLowerLevel – nivel de sobreventa del Stochastic.
  • Volume – volumen de la orden.
  • CandleType – tipo de datos de velas utilizados para los cálculos.

Indicadores

  • Media Móvil Simple
  • Índice de Fuerza Relativa
  • Oscilador Stochastic

Reglas de trading

  • Comprar cuando el precio está por encima de la SMA, el RSI está por debajo de RsiLowerLevel y ambas líneas del Stochastic están por debajo de StochLowerLevel.
  • Vender cuando el precio está por debajo de la SMA, el RSI está por encima de RsiUpperLevel y ambas líneas del Stochastic están por encima de StochUpperLevel.
  • Salir del largo cuando RSI o Stochastic sube por encima de sus niveles superiores.
  • Salir del corto cuando RSI o Stochastic cae por debajo de sus niveles inferiores.
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>
/// Combined RSI, Stochastic, and Moving Average strategy.
/// The MA defines the trend. Entries on RSI+Stochastic oversold/overbought in trend direction.
/// </summary>
public class RsiStochasticMaStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpperLevel;
	private readonly StrategyParam<decimal> _rsiLowerLevel;
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<decimal> _stochUpperLevel;
	private readonly StrategyParam<decimal> _stochLowerLevel;
	private readonly StrategyParam<decimal> _stopLossPct;
	private readonly StrategyParam<decimal> _takeProfitPct;
	private readonly StrategyParam<DataType> _candleType;

	private StochasticOscillator _stochastic;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public decimal RsiUpperLevel { get => _rsiUpperLevel.Value; set => _rsiUpperLevel.Value = value; }
	public decimal RsiLowerLevel { get => _rsiLowerLevel.Value; set => _rsiLowerLevel.Value = value; }
	public int MaPeriod { get => _maPeriod.Value; set => _maPeriod.Value = value; }
	public decimal StochUpperLevel { get => _stochUpperLevel.Value; set => _stochUpperLevel.Value = value; }
	public decimal StochLowerLevel { get => _stochLowerLevel.Value; set => _stochLowerLevel.Value = value; }
	public decimal StopLossPct { get => _stopLossPct.Value; set => _stopLossPct.Value = value; }
	public decimal TakeProfitPct { get => _takeProfitPct.Value; set => _takeProfitPct.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public RsiStochasticMaStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 3)
			.SetDisplay("RSI Period", "RSI calculation period", "RSI");

		_rsiUpperLevel = Param(nameof(RsiUpperLevel), 65m)
			.SetDisplay("RSI Upper Level", "RSI overbought level", "RSI");

		_rsiLowerLevel = Param(nameof(RsiLowerLevel), 35m)
			.SetDisplay("RSI Lower Level", "RSI oversold level", "RSI");

		_maPeriod = Param(nameof(MaPeriod), 20)
			.SetDisplay("MA Period", "Moving average period", "Trend");

		_stochUpperLevel = Param(nameof(StochUpperLevel), 60m)
			.SetDisplay("Stochastic Upper", "Stochastic overbought level", "Stochastic");

		_stochLowerLevel = Param(nameof(StochLowerLevel), 40m)
			.SetDisplay("Stochastic Lower", "Stochastic oversold level", "Stochastic");

		_stopLossPct = Param(nameof(StopLossPct), 2m)
			.SetDisplay("Stop Loss %", "Stop loss percentage", "Risk");

		_takeProfitPct = Param(nameof(TakeProfitPct), 3m)
			.SetDisplay("Take Profit %", "Take profit percentage", "Risk");

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

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

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

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var ma = new ExponentialMovingAverage { Length = MaPeriod };
		_stochastic = new StochasticOscillator();

		Indicators.Add(_stochastic);

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(ma, rsi, (candle, maValue, rsiValue) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				var stochResult = _stochastic.Process(candle);
				if (!_stochastic.IsFormed)
					return;

				var stochVal = (StochasticOscillatorValue)stochResult;
				if (stochVal.K is not decimal k || stochVal.D is not decimal d)
					return;

				var price = candle.ClosePrice;
				var isUpTrend = price > maValue;
				var isDownTrend = price < maValue;

				if (isUpTrend && rsiValue < RsiLowerLevel && k < StochLowerLevel && Position == 0)
				{
					BuyMarket();
				}
				else if (isDownTrend && rsiValue > RsiUpperLevel && k > StochUpperLevel && Position == 0)
				{
					SellMarket();
				}
			})
			.Start();

		StartProtection(
			takeProfit: new Unit(TakeProfitPct, UnitTypes.Percent),
			stopLoss: new Unit(StopLossPct, UnitTypes.Percent),
			useMarketOrders: true);

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