Ver en GitHub

Estrategia Experto RSI Stochastic MA

Descripción general

La Estrategia Experto RSI Stochastic MA es una conversión del asesor experto de MetaTrader 5 Expert_RSI_Stochastic_MA.mq5. La implementación en C# aprovecha la API de estrategias de alto nivel de StockSharp mientras reproduce la lógica original: un filtro de tendencia basado en una media móvil configurable, confirmación de momentum del RSI, y un oscilador Stochastic de doble línea para un timing preciso. El comportamiento protector replica el algoritmo fuente con un umbral de pérdida fijo opcional y una salida trailing impulsada por Stochastic.

Indicadores y Parámetros

La estrategia expone las mismas entradas que la versión MetaTrader y mantiene sus valores por defecto. Todos los parámetros están disponibles para optimización a través de la UI de StockSharp.

Categoría Parámetro Por defecto Descripción
General CandleType Marco temporal de 15 minutos Agregación de velas usada para los cálculos de indicadores.
Trading TradeVolume 0.01 Tamaño base de la orden en lotes/contratos.
RSI RsiPeriod 3 Número de barras usadas para calcular el RSI.
RSI RsiPriceType Cierre Precio aplicado para RSI (cierre, apertura, alto, bajo, mediano, típico, ponderado).
RSI RsiUpperLevel 80 Umbral de sobrecompra que activa las condiciones cortas.
RSI RsiLowerLevel 20 Umbral de sobreventa que activa las condiciones largas.
Stochastic StochKPeriod 6 Período de la línea %K.
Stochastic StochDPeriod 3 Período de la línea de suavizado %D.
Stochastic StochSlowing 3 Factor de desaceleración adicional aplicado a %K.
Stochastic StochUpperLevel 70 Nivel de sobrecompra compartido por ambas líneas Stochastic.
Stochastic StochLowerLevel 30 Nivel de sobreventa compartido por ambas líneas Stochastic.
Media Móvil MaMethod Simple Tipo de media móvil (simple, exponencial, suavizada, ponderada).
Media Móvil MaPriceType Cierre Precio aplicado para la media móvil.
Media Móvil MaPeriod 150 Longitud de la media móvil.
Media Móvil MaShift 0 Número de barras completadas usadas para desplazar el valor de la media móvil hacia atrás.
Riesgo AllowLossPoints 30 Máxima excursión adversa en puntos antes de salir de una operación perdedora (0 deshabilita).
Riesgo TrailingStopPoints 30 Distancia en puntos para el stop trailing basado en Stochastic (0 cierra en Stochastic sin trailing).

Cálculo de puntos – La implementación convierte los parámetros AllowLoss y TrailingStop en precios absolutos usando Security.PriceStep. Cuando el instrumento tiene 3 o 5 decimales, el valor se multiplica por 10 para emular el manejo de pips de MetaTrader.

Lógica de Trading

Configuración Largo

  1. Filtro de tendencia – El cierre de la vela debe mantenerse por encima de la media móvil desplazada.
  2. Confirmación de momentum – RSI debe estar por debajo de RsiLowerLevel.
  3. Timing – Ambas líneas Stochastic (%K y %D) deben estar por debajo de StochLowerLevel.
  4. Filtro de posición – Las órdenes largas solo se colocan cuando no existe exposición larga (Position <= 0). El tamaño de la orden es TradeVolume más cualquier cantidad requerida para cerrar una posición corta existente.

Configuración Corto

  1. Filtro de tendencia – El cierre de la vela debe estar por debajo de la media móvil desplazada.
  2. Confirmación de momentum – RSI debe superar RsiUpperLevel.
  3. Timing – Ambas líneas Stochastic deben estar por encima de StochUpperLevel.
  4. Filtro de posición – Las nuevas posiciones cortas requieren Position >= 0. La estrategia compensa los largos existentes automáticamente si es necesario.

Gestión de Salidas

  • Operaciones perdedoras
    • Cuando AllowLossPoints es cero, la estrategia espera a que la línea principal del Stochastic se mueva hacia el extremo opuesto (StochUpperLevel para largos, StochLowerLevel para cortos) antes de cerrar operaciones negativas.
    • Cuando AllowLossPoints es positivo, la estrategia convierte el valor en un desplazamiento de precio y cierra la operación tan pronto como la pérdida supere este umbral y el Stochastic vuelva dentro de la zona neutral (stochMain > StochLowerLevel para largos, < StochUpperLevel para cortos).
  • Salida trailing
    • Con TrailingStopPoints > 0, una vez que una operación es rentable y el Stochastic alcanza su zona extrema, se establece un stop trailing en cada vela finalizada. Para operaciones largas el stop sigue por debajo del precio; para cortas, sigue por encima.
    • Con TrailingStopPoints = 0, las operaciones rentables se cierran inmediatamente cuando el Stochastic alcanza el nivel extremo (igualando el comportamiento del EA original).
  • Disparador de trailing – Las actualizaciones de trailing solo ocurren en velas completadas, reflejando la implementación MQL que restringía las actualizaciones a una por barra.

Notas de Implementación

  • El desplazamiento de la media móvil se maneja almacenando valores recientes y leyendo el valor MaShift barras atrás, reproduciendo el parámetro shift de MetaTrader.
  • Las entradas de RSI y media móvil soportan múltiples precios aplicados para coincidir con las opciones de MetaTrader. Los cálculos del Stochastic dependen del oscilador incorporado de StockSharp (modo Low/High) y respetan las longitudes de suavizado configuradas.
  • Los umbrales de trailing y pérdida se miden en puntos. El ayudante escala automáticamente el valor para tamaños de tick típicos de FX (3 o 5 decimales) y por defecto usa un PriceStep en caso contrario.
  • La salida del gráfico incluye velas, la media móvil, RSI e indicadores Stochastic, permitiendo validación visual similar a la plantilla original.
  • No hay versión Python adjunta por solicitud; solo se proporciona la implementación en C#.

Consejos de Uso

  • Al desplegar en valores con tamaños de tick no convencionales, verifique que Security.PriceStep esté completado; de lo contrario se usará la conversión predeterminada (1 punto = 1 unidad de precio).
  • Combine el StartProtection incorporado o módulos de riesgo adicionales si se requiere mayor gestión de stop-loss o take-profit.
  • Optimice las longitudes de los indicadores y los umbrales de riesgo juntos — la estrategia expone intencionalmente todos los controles primarios del experto MetaTrader.
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>
/// Combines an SMA trend filter with RSI and Stochastic oscillators.
/// Enters long when price is above SMA, RSI is oversold and Stochastic is oversold.
/// Enters short when price is below SMA, RSI is overbought and Stochastic is overbought.
/// </summary>
public class ExpertRsiStochasticMaStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<decimal> _rsiUpperLevel;
	private readonly StrategyParam<decimal> _rsiLowerLevel;
	private readonly StrategyParam<int> _stochKPeriod;
	private readonly StrategyParam<int> _stochDPeriod;
	private readonly StrategyParam<decimal> _stochUpperLevel;
	private readonly StrategyParam<decimal> _stochLowerLevel;
	private readonly StrategyParam<int> _maPeriod;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	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 StochKPeriod
	{
		get => _stochKPeriod.Value;
		set => _stochKPeriod.Value = value;
	}

	public int StochDPeriod
	{
		get => _stochDPeriod.Value;
		set => _stochDPeriod.Value = value;
	}

	public decimal StochUpperLevel
	{
		get => _stochUpperLevel.Value;
		set => _stochUpperLevel.Value = value;
	}

	public decimal StochLowerLevel
	{
		get => _stochLowerLevel.Value;
		set => _stochLowerLevel.Value = value;
	}

	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	public ExpertRsiStochasticMaStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Time frame used for calculations", "General");

		_rsiPeriod = Param(nameof(RsiPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "Number of bars for RSI", "RSI");

		_rsiUpperLevel = Param(nameof(RsiUpperLevel), 80m)
			.SetDisplay("RSI Overbought", "Upper RSI threshold", "RSI");

		_rsiLowerLevel = Param(nameof(RsiLowerLevel), 20m)
			.SetDisplay("RSI Oversold", "Lower RSI threshold", "RSI");

		_stochKPeriod = Param(nameof(StochKPeriod), 6)
			.SetGreaterThanZero()
			.SetDisplay("%K Period", "Length of Stochastic %K", "Stochastic");

		_stochDPeriod = Param(nameof(StochDPeriod), 3)
			.SetGreaterThanZero()
			.SetDisplay("%D Period", "Length of Stochastic %D", "Stochastic");

		_stochUpperLevel = Param(nameof(StochUpperLevel), 70m)
			.SetDisplay("Stoch Overbought", "Upper Stochastic threshold", "Stochastic");

		_stochLowerLevel = Param(nameof(StochLowerLevel), 30m)
			.SetDisplay("Stoch Oversold", "Lower Stochastic threshold", "Stochastic");

		_maPeriod = Param(nameof(MaPeriod), 50)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Length of moving average", "Moving Average");
	}

	/// <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 sma = new SMA { Length = MaPeriod };
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var stoch = new StochasticOscillator();
		stoch.K.Length = StochKPeriod;
		stoch.D.Length = StochDPeriod;

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

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

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

		if (!smaValue.IsFinal || !rsiValue.IsFinal || !stochValue.IsFinal)
			return;

		var sma = smaValue.IsEmpty ? (decimal?)null : smaValue.GetValue<decimal>();
		var rsiVal = rsiValue.IsEmpty ? (decimal?)null : rsiValue.GetValue<decimal>();

		if (sma is not decimal smaDecimal || rsiVal is not decimal rsiDecimal)
			return;

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal stochK || stoch.D is not decimal stochD)
			return;

		var price = candle.ClosePrice;

		// Long entry: price above SMA, RSI oversold, Stochastic oversold
		if (price > smaDecimal && rsiDecimal < RsiLowerLevel && stochK < StochLowerLevel && stochD < StochLowerLevel)
		{
			if (Position <= 0)
				BuyMarket();
		}
		// Short entry: price below SMA, RSI overbought, Stochastic overbought
		else if (price < smaDecimal && rsiDecimal > RsiUpperLevel && stochK > StochUpperLevel && stochD > StochUpperLevel)
		{
			if (Position >= 0)
				SellMarket();
		}
		// Exit long: Stochastic overbought
		else if (Position > 0 && stochK > StochUpperLevel)
		{
			SellMarket();
		}
		// Exit short: Stochastic oversold
		else if (Position < 0 && stochK < StochLowerLevel)
		{
			BuyMarket();
		}
	}
}