Открыть на GitHub

Стратегия RSI Long Only with Confirmed Crossbacks

Стратегия ждёт, когда RSI опустится ниже порога и затем пересечёт его снизу вверх. Такое подтверждённое возвращение из зоны перепроданности открывает длинную позицию. Позиция закрывается при пересечении RSI уровня выхода. Параметры позволяют включить шорты, но по умолчанию они отключены.

Детали

  • Условия входа: RSI пересекает снизу вверх уровень перепроданности после нахождения ниже.
  • Направление: Лонг по умолчанию.
  • Условия выхода: RSI пересекает уровень выхода по лонгу или выполняются короткие правила.
  • Стопы: Нет.
  • Значения по умолчанию:
    • CandleType = 5 минут
    • RsiLength = 14
    • Oversold = 44
    • LongExitLevel = 70
    • ShortEntryLevel = 100
    • ShortExitLevel = 0
  • Фильтры:
    • Категория: Разворот
    • Направление: Лонг
    • Индикаторы: RSI
    • Стопы: Нет
    • Сложность: Базовая
    • Таймфрейм: Внутридневной
    • Сезонность: Нет
    • Нейросети: Нет
    • Дивергенция: Нет
    • Уровень риска: Средний
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 long only with confirmed crossbacks strategy using EMA crossover.
/// </summary>
public class RsiLongOnlyWithConfirmedCrossbacksStrategy : 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 RsiLongOnlyWithConfirmedCrossbacksStrategy()
	{
		_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); }
	}
}