Ver en GitHub

Exp RSIOMA Strategy

The Exp RSIOMA strategy uses the RSI of moving average (RSIOMA) indicator to trade trend reversals and breakouts. RSI values are smoothed by an additional moving average to form a signal line and histogram. The strategy supports four modes:

  1. Breakdown – trades when RSI crosses configured high/low levels.
  2. HistTwist – trades when histogram changes direction.
  3. SignalTwist – trades when the signal line changes direction.
  4. HistDisposition – trades when histogram crosses the signal line.

Positions can be opened or closed independently for long and short sides.

Details

  • Entry Criteria: depends on Mode
  • Long/Short: both
  • Exit Criteria: opposite signal
  • Stops: none
  • Default Values:
    • CandleType = 4 hour
    • RsiPeriod = 14
    • SignalPeriod = 21
    • HighLevel = 20
    • LowLevel = -20
  • Filters:
    • Category: Trend
    • Direction: Both
    • Indicators: RSI
    • Stops: No
    • Complexity: Intermediate
    • Timeframe: Intraday
    • Seasonality: No
    • Neural networks: No
    • Divergence: No
    • Risk level: Medium
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 based on the RSI crossover with an EMA of RSI (RSIOMA style).
/// Buys when RSI crosses above its EMA and sells when RSI crosses below.
/// </summary>
public class ExpRsiomaStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private decimal _prevEma;
	private bool _hasPrev;

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

	/// <summary>EMA smoothing period.</summary>
	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }

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

	public ExpRsiomaStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 21)
			.SetDisplay("RSI Period", "RSI calculation length", "Parameters")
			.SetGreaterThanZero();

		_emaPeriod = Param(nameof(EmaPeriod), 14)
			.SetDisplay("EMA Period", "EMA smoothing period", "Parameters")
			.SetGreaterThanZero();

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = 0m;
		_prevEma = 0m;
		_hasPrev = false;
	}

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

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

		_hasPrev = false;

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var rsiEma = new ExponentialMovingAverage { Length = EmaPeriod };

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

				var emaResult = rsiEma.Process(new DecimalIndicatorValue(rsiEma, rsiValue, candle.ServerTime) { IsFinal = true });

				if (!rsiEma.IsFormed)
					return;

				var emaValue = emaResult.ToDecimal();

				if (_hasPrev)
				{
					var crossUp = _prevRsi <= _prevEma && rsiValue > emaValue;
					var crossDown = _prevRsi >= _prevEma && rsiValue < emaValue;

					if (crossUp && Position == 0)
						BuyMarket();
					else if (crossDown && Position == 0)
						SellMarket();
				}

				_prevRsi = rsiValue;
				_prevEma = emaValue;
				_hasPrev = true;
			})
			.Start();

		StartProtection(
			takeProfit: new Unit(2, UnitTypes.Percent),
			stopLoss: new Unit(1, UnitTypes.Percent)
		);

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