Auf GitHub ansehen

Ausbruch-BB-Strategie

Überblick

Die Ausbruch-BB-Strategie repliziert den MetaTrader Expert Advisor Breakthrough_BB innerhalb der StockSharp High-Level-API. Das System kombiniert Bollinger Bänder mit einem schnellen einfachen gleitenden Durchschnitt, um explosive Ausbrüche zu erfassen, die auftreten, nachdem sich der Preis nahe den Bandgrenzen komprimiert hat. Trades werden ausschließlich auf abgeschlossenen Kerzen generiert, um Signale deterministisch zu halten und das ursprüngliche MQL5-Verhalten widerzuspiegeln.

Handelslogik

  • Trendfilter: Ein einfacher gleitender Durchschnitt (SMA) mit konfigurierbarem Zeitraum validiert die Trendrichtung. Die Strategie vergleicht den letzten SMA-Wert mit dem SMA-Wert von vier Kerzen zuvor. Long-Trades erfordern einen steigenden SMA, während Shorts einen fallenden Verlauf erfordern.
  • Bollinger Bänder Ausbruch: Die Strategie beobachtet, wie der Schlusskurs von vier Kerzen zuvor mit dem oberen oder unteren Bollinger Band interagierte, und vergleicht ihn mit dem jüngsten Schlusskurs. Ein gültiger Ausbruch tritt auf, wenn der Preis zwischen diesen zwei Zeitstempeln von innerhalb des Bandes nach außen wechselt.
  • Einzelpositionsmodell: Der Algorithmus hält maximal eine offene Position. Jeder offene Trade wird geschlossen, bevor neue Einstiege bewertet werden, um überlappende Engagements zu verhindern.

Einstiegsbedingungen

Long-Setup

  1. Der Schlusskurs von vier abgeschlossenen Kerzen zuvor lag unter dem oberen Bollinger Band.
  2. Der jüngste Schlusskurs schloss über dem aktuellen oberen Bollinger Band.
  3. Der auf der letzten Kerze berechnete SMA-Wert ist größer als der SMA-Wert von vier Kerzen zuvor (positive Steigung).
  4. Keine Position ist aktuell offen.

Short-Setup

  1. Der Schlusskurs von vier abgeschlossenen Kerzen zuvor lag über dem unteren Bollinger Band.
  2. Der jüngste Schlusskurs schloss unter dem aktuellen unteren Bollinger Band.
  3. Der auf der letzten Kerze berechnete SMA-Wert ist niedriger als der SMA-Wert von vier Kerzen zuvor (negative Steigung).
  4. Keine Position ist aktuell offen.

Wenn eine Einstiegsbedingung erfüllt ist, sendet die Strategie eine Marktorder mit dem konfigurierten Volumenparameter.

Ausstiegsregeln

  • Long-Position Ausstieg: Wenn ein Long-Trade aktiv ist und der letzte Schlusskurs unter die Bollinger-Mittellinie fällt, wird die Position sofort mit einer Markt-Verkaufsorder geschlossen.
  • Short-Position Ausstieg: Wenn ein Short-Trade offen ist und der letzte Schlusskurs über die Bollinger-Mittellinie steigt, wird die Position mit einer Markt-Kauforder gedeckt.

Diese Ausstiegsregeln imitieren den ursprünglichen Expert Advisor, der Trades entfernte, wann immer der Markt zur Bandmittellinie zurückkehrte.

Indikatoren

  • Einfacher gleitender Durchschnitt (SMA): Definiert die Richtungsneigung und liefert den Steigungsvergleich über ein Vier-Kerzen-Intervall.
  • Bollinger Bänder: Liefert die obere, mittlere und untere Hülle, die zur Erkennung von Ausbruchseinstiegen und zur Verwaltung von Ausstiegen verwendet werden.

Parameter

Name Beschreibung Standard Optimierbar
MaPeriod Länge des SMA für den Trendfilter. 9
BandsPeriod Rückblicklänge für Bollinger-Band-Berechnungen. 28
Deviation Standardabweichungsmultiplikator für Bollinger Bänder. 1.6
Volume Ordergröße (in Lots oder Kontrakten, je nach Instrument). 1
CandleType Von der Strategie verarbeiteter Kerzenaggregationstyp. Zeitrahmen 1 Stunde

Alle Parameter exponieren StockSharp StrategyParam-Metadaten, sodass sie in der UI angepasst oder im Designer optimiert werden können.

Datenanforderungen

  • Funktioniert mit jedem Instrument, das Kerzendaten bereitstellt, die mit dem ausgewählten CandleType kompatibel sind.
  • Signale werden nur auf abgeschlossenen Kerzen ausgewertet. Unvollständige Kerzen werden ignoriert, um die Logik deterministisch zu halten.
  • Die Standardkonfiguration verwendet stündliche Kerzen, aber jeder von der Datenquelle unterstützte Zeitrahmen kann angegeben werden.

Zusätzliche Hinweise

  • Der Algorithmus verzichtet auf Indikator-Historien-Abfragen und pflegt stattdessen einen rollierenden Vier-Kerzen-Cache für Schluss- und SMA-Werte, entsprechend den Projektrichtlinien.
  • Schutzfunktionen wie Stop-Loss oder Take-Profit können bei Bedarf über StartProtection hinzugefügt werden; sie sind kein Teil der ursprünglichen MQL-Implementierung und werden daher hier weggelassen.
  • Da die Strategie Marktorders ausgibt, stellen Sie ausreichende Liquidität auf dem gewählten Instrument sicher, um Slippage zu minimieren.
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 Bollinger Bands breakouts with a moving average trend filter.
/// </summary>
public class BreakthroughBbStrategy : Strategy
{
	private readonly StrategyParam<int> _maPeriod;
	private readonly StrategyParam<int> _bandsPeriod;
	private readonly StrategyParam<decimal> _deviation;
	private readonly StrategyParam<DataType> _candleType;

	private SimpleMovingAverage _sma;
	private BollingerBands _bollingerBands;

	private decimal? _closeLag0;
	private decimal? _closeLag1;
	private decimal? _closeLag2;
	private decimal? _closeLag3;

	private decimal? _maLag0;
	private decimal? _maLag1;
	private decimal? _maLag2;
	private decimal? _maLag3;

	/// <summary>
	/// Moving average period that defines the long term trend.
	/// </summary>
	public int MaPeriod
	{
		get => _maPeriod.Value;
		set => _maPeriod.Value = value;
	}

	/// <summary>
	/// Bollinger Bands lookback period.
	/// </summary>
	public int BandsPeriod
	{
		get => _bandsPeriod.Value;
		set => _bandsPeriod.Value = value;
	}

	/// <summary>
	/// Bollinger Bands width measured in standard deviations.
	/// </summary>
	public decimal Deviation
	{
		get => _deviation.Value;
		set => _deviation.Value = value;
	}


	/// <summary>
	/// Candle type processed by the strategy.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// Initializes a new instance of <see cref="BreakthroughBbStrategy"/>.
	/// </summary>
	public BreakthroughBbStrategy()
	{
		_maPeriod = Param(nameof(MaPeriod), 9)
			.SetGreaterThanZero()
			.SetDisplay("MA Period", "Simple moving average length", "Parameters")
			;

		_bandsPeriod = Param(nameof(BandsPeriod), 28)
			.SetGreaterThanZero()
			.SetDisplay("Bands Period", "Bollinger Bands lookback", "Parameters")
			;

		_deviation = Param(nameof(Deviation), 1.6m)
			.SetGreaterThanZero()
			.SetDisplay("Deviation", "Bollinger Bands width in deviations", "Parameters")
			;


		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle series processed by the strategy", "General");
	}

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

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

		_sma = default;
		_bollingerBands = default;

		_closeLag0 = null;
		_closeLag1 = null;
		_closeLag2 = null;
		_closeLag3 = null;

		_maLag0 = null;
		_maLag1 = null;
		_maLag2 = null;
		_maLag3 = null;
	}

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

		_sma = new SimpleMovingAverage { Length = MaPeriod };
		_bollingerBands = new BollingerBands
		{
			Length = BandsPeriod,
			Width = Deviation
		};

		var subscription = SubscribeCandles(CandleType);

		subscription
			.BindEx(_sma, _bollingerBands, ProcessCandle)
			.Start();
	}

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

		var smaValue = smaIndValue.IsFormed ? smaIndValue.ToDecimal() : 0m;
		var bb = bbValue as IBollingerBandsValue;
		var middleBand = bb?.MovingAverage ?? 0m;
		var upperBand = bb?.UpBand ?? 0m;
		var lowerBand = bb?.LowBand ?? 0m;

		var close = candle.ClosePrice;
		var maPrev4 = _maLag2;
		var closePrev4 = _closeLag2;

		if (_sma is null || _bollingerBands is null)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (!_sma.IsFormed || !_bollingerBands.IsFormed)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position > 0 && close < middleBand)
		{
			SellMarket();
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position < 0 && close > middleBand)
		{
			BuyMarket();
			UpdateHistory(close, smaValue);
			return;
		}

		if (maPrev4 is null || closePrev4 is null)
		{
			UpdateHistory(close, smaValue);
			return;
		}

		if (Position == 0)
		{
			if (closePrev4.Value < upperBand && close > upperBand && smaValue > maPrev4.Value)
			{
				BuyMarket();
				UpdateHistory(close, smaValue);
				return;
			}

			if (closePrev4.Value > lowerBand && close < lowerBand && smaValue < maPrev4.Value)
			{
				SellMarket();
				UpdateHistory(close, smaValue);
				return;
			}
		}

		UpdateHistory(close, smaValue);
	}

	private void UpdateHistory(decimal close, decimal maValue)
	{
		_maLag3 = _maLag2;
		_maLag2 = _maLag1;
		_maLag1 = _maLag0;
		_maLag0 = maValue;

		_closeLag3 = _closeLag2;
		_closeLag2 = _closeLag1;
		_closeLag1 = _closeLag0;
		_closeLag0 = close;
	}
}