Auf GitHub ansehen

Strategie zum Ausbruch der vorherigen Kerze

Diese Strategie repliziert den klassischen MetaTrader-Expert-Advisor "BreakOut" von Soubra2003. Sie überwacht das Hoch und Tief der zuletzt abgeschlossenen Kerze und reagiert, wenn der aktuelle Schlusskurs diese Referenzniveaus durchbricht. Der Ansatz ist vollständig symmetrisch: Long-Positionen werden bei bullischen Ausbrüchen eröffnet, und Short-Positionen werden bei bearischen Einbrüchen eröffnet. Optionale Stop-Loss- und Take-Profit-Puffer in Preiseinheiten ermöglichen es dem Benutzer, das Risiko zu begrenzen oder Gewinne zu sichern.

Überblick

  • Abonniert eine einzelne Kerzenserie (standardmäßig 1-Stunden-Zeitrahmen).
  • Speichert Hoch und Tief der vorherigen Kerze als Ausbruchsauslöser.
  • Handelt nur bei Kerzenschluss, um die ursprüngliche tick-basierte Logik ohne Intrabar-Daten zu spiegeln.
  • Unterstützt sowohl Long- als auch Short-Trades und bleibt immer flach, wenn keine Ausbruchsbedingung aktiv ist.

Handelsregeln

  1. Ausbruchseinstieg / Umkehr
    • Wenn der Schlusskurs der aktuellen abgeschlossenen Kerze strikt über dem Hoch der vorherigen Kerze liegt:
      • Jede offene Short-Position wird zu Marktpreisen geschlossen.
      • Unmittelbar danach wird eine neue Long-Position eröffnet (die Umkehr erfolgt innerhalb desselben Kerzenverarbeitungsschritts).
    • Wenn der Schlusskurs strikt unter dem Tief der vorherigen Kerze liegt:
      • Jede offene Long-Position wird zu Marktpreisen geschlossen.
      • Anschließend wird eine neue Short-Position eröffnet.
  2. Schützende Ausstiege (optional)
    • Wenn ein Stop-Loss-Offset konfiguriert ist (> 0), verlässt die Strategie ein Long, wenn der Schlusskurs offset Einheiten unter den Einstiegspreis fällt, oder verlässt ein Short, wenn der Schlusskurs offset Einheiten über den Einstiegspreis steigt.
    • Wenn ein Take-Profit-Offset konfiguriert ist (> 0), verlässt die Strategie ein Long, wenn der Schlusskurs offset Einheiten über den Einstiegspreis steigt, oder verlässt ein Short, wenn der Schlusskurs offset Einheiten unter den Einstiegspreis fällt.
  3. Zustandsreset
    • Nach jeder verarbeiteten Kerze werden das zuletzt gesehene Hoch und Tief zu den neuen Ausbruchs-Referenzniveaus.

Parameter

  • Candle Type – Datentyp für das Abonnement (standardmäßig stündlicher Zeitrahmen). Stellen Sie dies auf die Balkengröße ein, die dem in MetaTrader für den ursprünglichen Expert verwendeten Chart entspricht.
  • Stop Loss – Abstand in absoluten Preiseinheiten zwischen dem Einstiegspreis und dem Schutz-Stop. Bei 0 belassen, um die Stop-Loss-Behandlung zu deaktivieren.
  • Take Profit – Abstand in absoluten Preiseinheiten zwischen dem Einstiegspreis und dem Gewinnziel. Bei 0 belassen, um die Take-Profit-Behandlung zu deaktivieren.

Hinweise

  • Die Stop-Loss- und Take-Profit-Berechnungen werden auf Kerzenschlusspreisen durchgeführt. Die ursprüngliche MQL4-Version hängte statische SL/TP-Niveaus an die Orders; in StockSharp werden die Ausstiege simuliert, indem Marktorders gesendet werden, sobald die Schwellenwerte erreicht sind.
  • Verwenden Sie instrumentenspezifische Preiserhöhungen beim Konfigurieren der Offsets. Wenn das Instrument beispielsweise mit einer Tick-Größe von 0.01 handelt und Sie einen 20-Tick-Stop möchten, setzen Sie den Stop-Loss-Parameter auf 0.20.
  • Da die Logik immer auf die unmittelbar vorangehende Kerze verweist, funktioniert die Strategie am besten bei Trendingstrumenten oder während hochvolatiler Sitzungen, bei denen Ausbrüche bedeutungsvoll sind.

Herkunft

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>
/// Breakout strategy that trades when the close crosses the previous candle's high or low.
/// Ported from the BreakOut.mq4 expert by Soubra2003.
/// </summary>
public class PreviousCandleBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<decimal> _stopLossOffset;
	private readonly StrategyParam<decimal> _takeProfitOffset;

	private decimal? _previousHigh;
	private decimal? _previousLow;
	private decimal _entryPrice;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public decimal StopLossOffset { get => _stopLossOffset.Value; set => _stopLossOffset.Value = value; }
	public decimal TakeProfitOffset { get => _takeProfitOffset.Value; set => _takeProfitOffset.Value = value; }

	public PreviousCandleBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromDays(1).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for candle subscription", "General");

		_stopLossOffset = Param(nameof(StopLossOffset), 1000m)
			.SetDisplay("Stop Loss", "Price distance for the stop-loss. Set 0 to disable.", "Risk")
			;

		_takeProfitOffset = Param(nameof(TakeProfitOffset), 1500m)
			.SetDisplay("Take Profit", "Price distance for the take-profit. Set 0 to disable.", "Risk")
			;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_previousHigh = null;
		_previousLow = null;
		_entryPrice = 0m;
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, CandleType);
	}

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

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

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

		if (_previousHigh is null || _previousLow is null)
		{
			// Store the first finished candle to obtain reference high/low levels.
			_previousHigh = candle.HighPrice;
			_previousLow = candle.LowPrice;
			return;
		}

		var previousHigh = _previousHigh.Value;
		var previousLow = _previousLow.Value;
		var close = candle.ClosePrice;

		var breakoutAbove = close > previousHigh;
		var breakoutBelow = close < previousLow;

		// Manage protective exits while a position is open.
		if (Position > 0)
		{
			if (StopLossOffset > 0m && close <= _entryPrice - StopLossOffset)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}
			else if (TakeProfitOffset > 0m && close >= _entryPrice + TakeProfitOffset)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}
		}
		else if (Position < 0)
		{
			if (StopLossOffset > 0m && close >= _entryPrice + StopLossOffset)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}
			else if (TakeProfitOffset > 0m && close <= _entryPrice - TakeProfitOffset)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}
		}

		// Breakout above the previous high opens or reverses into a long position.
		if (breakoutAbove)
		{
			if (Position < 0)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}

			if (Position <= 0)
			{
				BuyMarket();
				_entryPrice = close;
			}
		}
		else if (breakoutBelow)
		{
			// Breakout below the previous low opens or reverses into a short position.
			if (Position > 0)
			{
				if (Position > 0) SellMarket(); else if (Position < 0) BuyMarket();
				_entryPrice = 0m;
			}

			if (Position >= 0)
			{
				SellMarket();
				_entryPrice = close;
			}
		}

		_previousHigh = candle.HighPrice;
		_previousLow = candle.LowPrice;
	}
}