View on GitHub

RSI & Backed-Weighted MA Strategy

Strategy uses the Relative Strength Index and a retro weighted moving average with a rate-of-change filter. Long positions open when RSI exceeds the threshold and MA ROC is below the set level, while short positions open on the opposite conditions. The system applies an ATR-based trailing stop and fixed ratio position sizing.

Details

  • Entry Criteria:
    • Long: RSI >= RsiLongSignal and MA ROC <= RocMaLongSignal
    • Short: RSI <= RsiShortSignal and MA ROC >= RocMaShortSignal
  • Long/Short: Both directions.
  • Exit Criteria: Opposite signal, stop loss or trailing stop.
  • Stops: Yes, ATR trailing stop and max loss percent.
  • Default Values:
    • RsiLength = 20
    • MaType = RWMA
    • MaLength = 19
    • RsiLongSignal = 60
    • RsiShortSignal = 40
    • TakeProfitActivation = 5
    • TrailingPercent = 3
    • MaxLossPercent = 10
    • FixedRatio = 400
    • IncreasingOrderAmount = 200
    • CandleType = TimeSpan.FromMinutes(1)
  • Filters:
    • Category: Trend following
    • Direction: Both
    • Indicators: RSI, Moving Average, ATR
    • Stops: Yes
    • Complexity: High
    • Timeframe: Any
    • Seasonality: No
    • Neural networks: No
    • Divergence: No
    • Risk level: Medium
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>
/// RSI backed weighted MA strategy using EMA crossover.
/// </summary>
public class RsiBackedWeightedMaStrategy : Strategy
{
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<DataType> _candleType;

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

	public RsiBackedWeightedMaStrategy()
	{
		_slowLength = Param(nameof(SlowLength), 40)
			.SetGreaterThanZero()
			.SetDisplay("Slow Length", "Slow EMA period", "General");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
		=> [(Security, CandleType)];

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		var fast = new ExponentialMovingAverage { Length = 14 };
		var slow = new ExponentialMovingAverage { Length = SlowLength };
		var prevF = 0m; var prevS = 0m; var init = false;
		var lastSignal = DateTimeOffset.MinValue;
		var cooldown = TimeSpan.FromMinutes(360);
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, (candle, f, s) =>
		{
			if (candle.State != CandleStates.Finished) return;
			if (!fast.IsFormed || !slow.IsFormed) return;
			if (!init) { prevF = f; prevS = s; init = true; return; }
			if (candle.OpenTime - lastSignal >= cooldown)
			{
				if (prevF <= prevS && f > s && Position <= 0) { BuyMarket(); lastSignal = candle.OpenTime; }
				else if (prevF >= prevS && f < s && Position >= 0) { SellMarket(); lastSignal = candle.OpenTime; }
			}
			prevF = f; prevS = s;
		}).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}
}