Ver no GitHub

Stochastic RSI OHLC Strategy

This strategy builds OHLC bars from the Stochastic RSI indicator and trades on momentum shifts. It calculates RSI for high, low and close prices and applies a stochastic oscillator to each series. A long position opens when Stochastic RSI rises from a pivot and crosses above the long entry level. A short position opens when it falls from a pivot and crosses below the short entry level.

Details

  • Entry Criteria:
    • Long: Stochastic RSI turns up and any of the last three values exceed LongEntry after a low pivot.
    • Short: Stochastic RSI turns down and any of the last three values fall below ShortEntry after a high pivot.
  • Long/Short: Both sides.
  • Exit Criteria: Opposite signal.
  • Stops: None.
  • Default Values:
    • RSI Length = 14
    • K Length = 14
    • D Length = 3
    • LongEntry = 30
    • ShortEntry = 60
    • LongPivot = 2
    • ShortPivot = 98
  • Filters:
    • Category: Momentum
    • Direction: Both
    • Indicators: RSI, Stochastic
    • Stops: No
    • Complexity: Medium
    • Timeframe: Short-term
    • 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>
/// Stochastic RSI OHLC strategy using EMA crossover.
/// </summary>
public class StochasticRsiOhlcStrategy : 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 StochasticRsiOhlcStrategy()
	{
		_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); }
	}
}