Auf GitHub ansehen

RoBoost-Strategie

Diese Strategie ist eine C#-Adaption des ursprünglichen MQL4-Expertenberaters RoBoostj. Sie handelt ein einzelnes Instrument unter Verwendung RSI-basierter Signale kombiniert mit einfacher Preismomentum-Erkennung. Die Strategie arbeitet auf einem ausgewählten Kerzentyp (Standard: 1-Stunden-Kerzen).

Logik

  • Wenn der vorherige Schlusskurs höher als der aktuelle ist und der RSI-Wert unter den RSI Down-Schwellenwert fällt, eröffnet die Strategie eine Short-Position.
  • Wenn der vorherige Schlusskurs niedriger oder gleich dem aktuellen ist und der RSI-Wert über den RSI Up-Schwellenwert steigt, eröffnet die Strategie eine Long-Position.
  • Aktive Positionen werden mit folgenden Risikoinstrumenten verwaltet:
    • Feste Take Profit- und Stop Loss-Niveaus in Preiseinheiten.
    • Optionaler Trailing Stop, der aktiviert wird, wenn der Trade um die Trail Start- Distanz ins Plus läuft. Nach Aktivierung folgt der Stop-Preis dem Preis um die Trail Step-Distanz.

Parameter

Name Beschreibung
CandleType Kerzenserie für Berechnungen.
RsiPeriod Periodenlänge des RSI-Indikators.
RsiUp RSI-Schwellenwert für Long-Einstiege.
RsiDown RSI-Schwellenwert für Short-Einstiege.
TakeProfit Take-Profit-Abstand vom Eintrittspreis (Punkte).
StopLoss Stop-Loss-Abstand vom Eintrittspreis (Punkte).
UseTrailing Aktiviert die Trailing-Stop-Logik.
TrailStart Abstand in Punkten, ab dem der Trailing Stop aktiv wird.
TrailStep Abstand in Punkten, der vom aktuellen Preis gehalten wird,
wenn der Trailing Stop aktiv ist.

Alle Abstände werden in absoluten Preiseinheiten ausgedrückt und müssen je nach Tick-Größe des Instruments angepasst werden.

Verwendung

  1. Füge die Strategie zu deinem Projekt hinzu oder öffne sie im StockSharp Designer.
  2. Konfiguriere die Parameter nach deinen Handelspräferenzen.
  3. Starte die Strategie. Sie abonniert automatisch die gewählte Kerzenserie und verwaltet Trades basierend auf RSI-Werten und Kerzenschlusskursen.

Die Strategie ist für Ausbildungszwecke gedacht und sollte an historischen Daten getestet werden, bevor sie auf Live-Märkten eingesetzt wird.

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>
/// RSI based strategy converted from the original RoBoostj MQL4 robot.
/// Opens long or short positions depending on price momentum and RSI values.
/// Includes optional trailing stop management.
/// </summary>
public class RoBoostStrategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<int> _rsiUp;
	private readonly StrategyParam<int> _rsiDown;
	private readonly StrategyParam<bool> _useTrailing;
	private readonly StrategyParam<decimal> _trailStart;
	private readonly StrategyParam<decimal> _trailStep;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private bool _isLong;
	private decimal _trailingStopPrice;
	private decimal _previousClose;
	private bool _isFirst = true;

	/// <summary>
	/// Take profit distance from entry price.
	/// </summary>
	public decimal TakeProfit
	{
		get => _takeProfit.Value;
		set => _takeProfit.Value = value;
	}

	/// <summary>
	/// Stop loss distance from entry price.
	/// </summary>
	public decimal StopLoss
	{
		get => _stopLoss.Value;
		set => _stopLoss.Value = value;
	}

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

	/// <summary>
	/// RSI threshold for long entries.
	/// </summary>
	public int RsiUp
	{
		get => _rsiUp.Value;
		set => _rsiUp.Value = value;
	}

	/// <summary>
	/// RSI threshold for short entries.
	/// </summary>
	public int RsiDown
	{
		get => _rsiDown.Value;
		set => _rsiDown.Value = value;
	}

	/// <summary>
	/// Enables trailing stop logic.
	/// </summary>
	public bool UseTrailing
	{
		get => _useTrailing.Value;
		set => _useTrailing.Value = value;
	}

	/// <summary>
	/// Distance at which trailing stop becomes active.
	/// </summary>
	public decimal TrailStart
	{
		get => _trailStart.Value;
		set => _trailStart.Value = value;
	}

	/// <summary>
	/// Distance maintained from current price when trailing stop is active.
	/// </summary>
	public decimal TrailStep
	{
		get => _trailStep.Value;
		set => _trailStep.Value = value;
	}

	/// <summary>
	/// Type of candles used for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="RoBoostStrategy"/>.
	/// </summary>
	public RoBoostStrategy()
	{
		_takeProfit = Param(nameof(TakeProfit), 500m)
			.SetGreaterThanZero()
			.SetDisplay("Take Profit", "Take profit distance in points", "Risk Management");

		_stopLoss = Param(nameof(StopLoss), 1000m)
			.SetGreaterThanZero()
			.SetDisplay("Stop Loss", "Stop loss distance in points", "Risk Management");

		_rsiPeriod = Param(nameof(RsiPeriod), 7)
			.SetGreaterThanZero()
			.SetDisplay("RSI Period", "RSI calculation length", "Indicator")
			
			.SetOptimize(5, 20, 1);

		_rsiUp = Param(nameof(RsiUp), 50)
			.SetDisplay("RSI Up", "RSI threshold for longs", "Indicator")
			
			.SetOptimize(45, 70, 5);

		_rsiDown = Param(nameof(RsiDown), 50)
			.SetDisplay("RSI Down", "RSI threshold for shorts", "Indicator")
			
			.SetOptimize(30, 55, 5);

		_useTrailing = Param(nameof(UseTrailing), false)
			.SetDisplay("Use Trailing", "Enable trailing stop", "Risk Management");

		_trailStart = Param(nameof(TrailStart), 5m)
			.SetGreaterThanZero()
			.SetDisplay("Trail Start", "Profit distance to activate trailing", "Risk Management");

		_trailStep = Param(nameof(TrailStep), 2m)
			.SetGreaterThanZero()
			.SetDisplay("Trail Step", "Distance between price and trailing stop", "Risk Management");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles used", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_entryPrice = 0m;
		_isLong = false;
		_trailingStopPrice = 0m;
		_previousClose = 0m;
		_isFirst = true;
	}

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

		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();

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

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

		if (!IsFormedAndOnlineAndAllowTrading())
			return;

		var currentClose = candle.ClosePrice;

		if (_isFirst)
		{
			_previousClose = currentClose;
			_isFirst = false;
			return;
		}

		if (Position == 0)
		{
			if (_previousClose > currentClose && rsiValue < RsiDown)
			{
				SellMarket();
				_entryPrice = currentClose;
				_isLong = false;
				_trailingStopPrice = 0m;
			}
			else if (_previousClose <= currentClose && rsiValue >= RsiUp)
			{
				BuyMarket();
				_entryPrice = currentClose;
				_isLong = true;
				_trailingStopPrice = 0m;
			}
		}
		else
		{
			ManagePosition(currentClose);
		}

		_previousClose = currentClose;
	}

	private void ManagePosition(decimal currentPrice)
	{
		if (_entryPrice == 0m)
			return;

		if (_isLong)
		{
			var profit = currentPrice - _entryPrice;
			if (profit >= TakeProfit || -profit >= StopLoss)
			{
				SellMarket();
				return;
			}

			if (UseTrailing)
			{
				if (profit >= TrailStart)
				{
					var newStop = currentPrice - TrailStep;
					if (_trailingStopPrice < newStop)
						_trailingStopPrice = newStop;
				}

				if (_trailingStopPrice != 0m && currentPrice <= _trailingStopPrice)
					SellMarket();
			}
		}
		else
		{
			var profit = _entryPrice - currentPrice;
			if (profit >= TakeProfit || -profit >= StopLoss)
			{
				BuyMarket();
				return;
			}

			if (UseTrailing)
			{
				if (profit >= TrailStart)
				{
					var newStop = currentPrice + TrailStep;
					if (_trailingStopPrice == 0m || _trailingStopPrice > newStop)
						_trailingStopPrice = newStop;
				}

				if (_trailingStopPrice != 0m && currentPrice >= _trailingStopPrice)
					BuyMarket();
			}
		}
	}
}