Auf GitHub ansehen

JBrainUltraRSI-Strategie

Diese Beispielstrategie kombiniert den Relative Strength Index (RSI) und den Stochastik-Oszillator zur Generierung von Handelssignalen. Die Idee leitet sich vom ursprünglichen MetaTrader Expert Advisor ab, der die Indikatoren JBrainTrendSig1 und UltraRSI verwendete. In dieser Anpassung dient der Stochastik-Oszillator als Trendfilter, während der RSI Einstiegssignale liefert.

Funktionsweise

  1. Indikatoren
    • RSI: Misst den Momentum durch Vergleich aktueller Gewinne und Verluste. Ein Kreuz über das Niveau 50 zeigt bullischen Momentum an, während ein Kreuz unter 50 bärischen Momentum anzeigt.
    • Stochastik-Oszillator: Bewertet die Position des Schlusskurses relativ zur jüngsten Handelsspanne. Kreuzungen der %K- und %D-Linien bestätigen die Trendrichtung.
  2. Modi
    • JBrainSig1Filter – RSI generiert Signale und der Stochastik-Oszillator bestätigt die Richtung.
    • UltraRsiFilter – Der Stochastik-Oszillator liefert Signale, gefiltert durch den RSI.
    • Composition – Signale werden nur genommen, wenn beide Indikatoren in der Richtung übereinstimmen.
  3. Handelsregeln
    • Eine Long-Position wird eröffnet, wenn ein Kaufsignal erscheint und keine Short-Position vorhanden oder offen ist.
    • Eine Short-Position wird eröffnet, wenn ein Verkaufssignal erscheint und keine Long-Position vorhanden oder offen ist.
    • Umkehrsignale schließen bestehende Positionen, wenn erlaubt.

Parameter

Parameter Beschreibung
RsiPeriod RSI-Berechnungszeitraum.
StochLength %K-Zeitraum für den Stochastik-Oszillator.
SignalLength %D-Zeitraum für den Stochastik-Oszillator.
Mode Modus zur Kombination der Indikatoren.
AllowLongEntry / AllowShortEntry Berechtigungen zum Öffnen von Long- oder Short-Positionen.
AllowLongExit / AllowShortExit Berechtigungen zum Schließen von Long- oder Short-Positionen.
CandleType Kerzen-Zeitrahmen, der von der Strategie verwendet wird.

Hinweise

  • Die Strategie verwendet die High-Level-API von StockSharp mit Bind / BindEx für die Indikatorverarbeitung.
  • Stops und Ziele können mit dem eingebauten Schutzmechanismus StartProtection() konfiguriert werden.
  • Die Beispielvisualisierung zeichnet Kerzen, Indikatoren und eigene Trades, wenn ein Diagrammbereich verfügbar ist.

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 combining RSI and Stochastic oscillator signals.
/// </summary>
public class JBrainUltraRsiStrategy : Strategy
{
        /// <summary>
        /// Combination modes for indicators.
        /// </summary>
        public enum AlgorithmModes
        {
                JBrainSig1Filter,
                UltraRsiFilter,
                Composition
        }

	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _stochLength;
	private readonly StrategyParam<int> _signalLength;
	private readonly StrategyParam<AlgorithmModes> _mode;
	private readonly StrategyParam<bool> _allowLongEntry;
	private readonly StrategyParam<bool> _allowShortEntry;
	private readonly StrategyParam<bool> _allowLongExit;
	private readonly StrategyParam<bool> _allowShortExit;
	private readonly StrategyParam<DataType> _candleType;
	
	private RelativeStrengthIndex _rsi;
	private StochasticOscillator _stochastic;
	private decimal? _prevRsi;
	private decimal? _prevK;
	private decimal? _prevD;
	
	/// <summary>
	/// RSI calculation period.
	/// </summary>
	public int RsiPeriod
	{
		get => _rsiPeriod.Value;
		set => _rsiPeriod.Value = value;
	}
	
	/// <summary>
	/// Stochastic %K period.
	/// </summary>
	public int StochLength
	{
		get => _stochLength.Value;
		set => _stochLength.Value = value;
	}
	
	/// <summary>
	/// Stochastic %D period.
	/// </summary>
	public int SignalLength
	{
		get => _signalLength.Value;
		set => _signalLength.Value = value;
	}
	
	/// <summary>
	/// Mode combining indicators.
	/// </summary>
	public AlgorithmModes Mode
	{
		get => _mode.Value;
		set => _mode.Value = value;
	}
	
	/// <summary>
	/// Permission to open long positions.
	/// </summary>
	public bool AllowLongEntry
	{
		get => _allowLongEntry.Value;
		set => _allowLongEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to open short positions.
	/// </summary>
	public bool AllowShortEntry
	{
		get => _allowShortEntry.Value;
		set => _allowShortEntry.Value = value;
	}
	
	/// <summary>
	/// Permission to close long positions.
	/// </summary>
	public bool AllowLongExit
	{
		get => _allowLongExit.Value;
		set => _allowLongExit.Value = value;
	}
	
	/// <summary>
	/// Permission to close short positions.
	/// </summary>
	public bool AllowShortExit
	{
		get => _allowShortExit.Value;
		set => _allowShortExit.Value = value;
	}
	
	/// <summary>
	/// Candle type to process.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}
	
	/// <summary>
	/// Initializes a new instance of <see cref="JBrainUltraRsiStrategy"/>.
	/// </summary>
	public JBrainUltraRsiStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 13)
		.SetGreaterThanZero()
		.SetDisplay("RSI Period", "RSI calculation period", "Indicators")
		;
		
		_stochLength = Param(nameof(StochLength), 9)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %K", "Period for %K line", "Indicators")
		;
		
		_signalLength = Param(nameof(SignalLength), 3)
		.SetGreaterThanZero()
		.SetDisplay("Stochastic %D", "Period for %D line", "Indicators")
		;
		
		_mode = Param(nameof(Mode), AlgorithmModes.Composition)
		.SetDisplay("Mode", "Algorithm to enter the market", "General");
		
		_allowLongEntry = Param(nameof(AllowLongEntry), true)
		.SetDisplay("Allow Long Entry", "Permission to open long positions", "Trading");
		
		_allowShortEntry = Param(nameof(AllowShortEntry), true)
		.SetDisplay("Allow Short Entry", "Permission to open short positions", "Trading");
		
		_allowLongExit = Param(nameof(AllowLongExit), true)
		.SetDisplay("Allow Long Exit", "Permission to close long positions", "Trading");
		
		_allowShortExit = Param(nameof(AllowShortExit), true)
		.SetDisplay("Allow Short Exit", "Permission to close short positions", "Trading");
		
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
		.SetDisplay("Candle Type", "Type of candles", "General");
	}
	
	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}
	
	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		
		_rsi = default;
		_stochastic = default;
		_prevRsi = default;
		_prevK = default;
		_prevD = default;
	}
	
	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		
		StartProtection(null, null);
		
		_rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		_stochastic = new StochasticOscillator
		{
			K = { Length = StochLength },
			D = { Length = SignalLength },
		};
		
		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(_stochastic, ProcessCandle)
			.Start();

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

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

		// process RSI manually
		var rsiResult = _rsi.Process(candle.ClosePrice, candle.OpenTime, true);
		if (!rsiResult.IsFormed)
			return;

		var rsi = rsiResult.ToDecimal();

		var stoch = (StochasticOscillatorValue)stochValue;
		if (stoch.K is not decimal k || stoch.D is not decimal d)
		{
			_prevRsi = rsi;
			return;
		}

		var rsiUp = _prevRsi is decimal pr && pr <= 50m && rsi > 50m;
		var rsiDown = _prevRsi is decimal pr2 && pr2 >= 50m && rsi < 50m;
		var stochUp = _prevK is decimal pk && _prevD is decimal pd && pk <= pd && k > d;
		var stochDown = _prevK is decimal pk2 && _prevD is decimal pd2 && pk2 >= pd2 && k < d;

		var buySignal = false;
		var sellSignal = false;

		switch (Mode)
		{
			case AlgorithmModes.JBrainSig1Filter:
				buySignal = rsiUp && k > d;
				sellSignal = rsiDown && k < d;
				break;
			case AlgorithmModes.UltraRsiFilter:
				buySignal = stochUp && rsi > 50m;
				sellSignal = stochDown && rsi < 50m;
				break;
			case AlgorithmModes.Composition:
				buySignal = rsiUp && stochUp;
				sellSignal = rsiDown && stochDown;
				break;
		}

		if (buySignal)
		{
			if (Position < 0 && AllowShortExit)
				BuyMarket();
			if (AllowLongEntry && Position <= 0)
				BuyMarket();
		}
		else if (sellSignal)
		{
			if (Position > 0 && AllowLongExit)
				SellMarket();
			if (AllowShortEntry && Position >= 0)
				SellMarket();
		}

		_prevRsi = rsi;
		_prevK = k;
		_prevD = d;
	}
}