Auf GitHub ansehen

VR Steals 2-Strategie

Diese Strategie ist eine StockSharp-Konvertierung des MetaTrader-5-Experten "VR---STEALS-2". Sie eröffnet eine einzelne Long-Position und demonstriert einfaches Positionsmanagement ohne Indikatoren.

Funktionsweise

  1. Beim Start kauft die Strategie über BuyMarket und speichert den Einstiegspreis.
  2. Candledaten (standardmäßig 1 Minute) werden über SubscribeCandles abonniert.
  3. Für jede abgeschlossene Kerze:
    • Wenn sich der Preis um Breakeven Schritte zugunsten des Trades bewegt hat, wird das Stop-Level um BreakevenOffset Schritte über den Einstieg verschoben.
    • Erreicht der Preis den Einstieg plus TakeProfit Schritte, wird die Position geschlossen.
    • Fällt der Preis auf das Stop-Level (initial StopLoss unterhalb des Einstiegs oder der verschobene Break-Even-Stop), wird die Position geschlossen.
  4. Nach dem Ausstieg eröffnet die Strategie keine neuen Positionen.

Parameter

Name Beschreibung Standard
TakeProfit Abstand in Preisschritten zum Take-Profit-Level. 50
StopLoss Anfänglicher Stop-Abstand in Preisschritten. 50
Breakeven Gewinn in Schritten, der zum Aktivieren des Break-Even-Stops benötigt wird. 20
BreakevenOffset Versatz über den Einstieg beim Setzen des Break-Even-Stops. 9
CandleType Kerzentyp für die Preisverarbeitung. 1-Minuten-Zeitrahmen

StartProtection() wird verwendet, um den integrierten Positionsschutz zu aktivieren.

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>
/// Opens positions based on SMA trend direction, manages with fixed take profit,
/// stop loss and breakeven levels.
/// </summary>
public class VRSteals2Strategy : Strategy
{
	private readonly StrategyParam<decimal> _takeProfit;
	private readonly StrategyParam<decimal> _stopLoss;
	private readonly StrategyParam<decimal> _breakeven;
	private readonly StrategyParam<decimal> _breakevenOffset;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _entryPrice;
	private decimal _stopPrice;
	private bool _breakevenActivated;
	private decimal _previousFast;
	private decimal _previousSlow;
	private bool _maInitialized;

	public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
	public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
	public decimal Breakeven { get => _breakeven.Value; set => _breakeven.Value = value; }
	public decimal BreakevenOffset { get => _breakevenOffset.Value; set => _breakevenOffset.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public VRSteals2Strategy()
	{
		_takeProfit = Param(nameof(TakeProfit), 50m)
			.SetDisplay("Take Profit", "Distance to take profit in steps", "General");
		_stopLoss = Param(nameof(StopLoss), 50m)
			.SetDisplay("Stop Loss", "Distance to stop loss in steps", "General");
		_breakeven = Param(nameof(Breakeven), 20m)
			.SetDisplay("Breakeven", "Distance to activate breakeven in steps", "General");
		_breakevenOffset = Param(nameof(BreakevenOffset), 9m)
			.SetDisplay("Breakeven Offset", "Offset applied when breakeven is triggered", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(30).TimeFrame())
			.SetDisplay("Candle Type", "Type of candles to process", "General");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_entryPrice = 0m;
		_stopPrice = 0m;
		_breakevenActivated = false;
		_previousFast = 0m;
		_previousSlow = 0m;
		_maInitialized = false;
	}

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

		_entryPrice = 0m;
		_breakevenActivated = false;

		var fastSma = new SimpleMovingAverage { Length = 8 };
		var slowSma = new SimpleMovingAverage { Length = 34 };

		var sub = SubscribeCandles(CandleType);
		sub.Bind(fastSma, slowSma, (candle, fast, slow) =>
		{
			if (candle.State != CandleStates.Finished)
				return;

			var price = candle.ClosePrice;
			var step = Security?.PriceStep ?? 1m;

			// Manage existing long position
			if (Position > 0)
			{
				if (!_breakevenActivated && Breakeven > 0m && price >= _entryPrice + Breakeven * step)
				{
					_stopPrice = _entryPrice + BreakevenOffset * step;
					_breakevenActivated = true;
				}

				if (TakeProfit > 0m && price >= _entryPrice + TakeProfit * step)
				{
					SellMarket();
					_entryPrice = 0m;
					_breakevenActivated = false;
					return;
				}

				var stop = _breakevenActivated
					? _stopPrice
					: (StopLoss > 0m ? _entryPrice - StopLoss * step : decimal.MinValue);

				if (price <= stop)
				{
					SellMarket();
					_entryPrice = 0m;
					_breakevenActivated = false;
					return;
				}
			}
			// Manage existing short position
			else if (Position < 0)
			{
				if (!_breakevenActivated && Breakeven > 0m && price <= _entryPrice - Breakeven * step)
				{
					_stopPrice = _entryPrice - BreakevenOffset * step;
					_breakevenActivated = true;
				}

				if (TakeProfit > 0m && price <= _entryPrice - TakeProfit * step)
				{
					BuyMarket();
					_entryPrice = 0m;
					_breakevenActivated = false;
					return;
				}

				var stop = _breakevenActivated
					? _stopPrice
					: (StopLoss > 0m ? _entryPrice + StopLoss * step : decimal.MaxValue);

				if (price >= stop)
				{
					BuyMarket();
					_entryPrice = 0m;
					_breakevenActivated = false;
					return;
				}
			}

			// Entry signals based on SMA cross
			if (Position == 0)
			{
				if (_maInitialized && _previousFast <= _previousSlow && fast > slow)
				{
					BuyMarket();
					_entryPrice = price;
					_breakevenActivated = false;
				}
				else if (_maInitialized && _previousFast >= _previousSlow && fast < slow)
				{
					SellMarket();
					_entryPrice = price;
					_breakevenActivated = false;
				}
			}

			_previousFast = fast;
			_previousSlow = slow;
			_maInitialized = true;
		}).Start();

		StartProtection(
			new Unit(2000m, UnitTypes.Absolute),
			new Unit(1000m, UnitTypes.Absolute));
	}
}