Auf GitHub ansehen

Bollinger Band Squeeze Breakout-Strategie

Überblick

Die Strategie repliziert den ursprünglichen MetaTrader 4-Expert Advisor "BOLINGER BAND SQUEEZE" mit der StockSharp High-Level-API. Sie sucht nach Perioden, in denen sich Bollinger Bands zusammenziehen, und tritt dann in Trades ein, sobald sich die Bänder ausdehnen, sofern Momentum- und Trendfilter die Bewegung bestätigen. Die Konvertierung behält die Multi-Timeframe-Bestätigungslogik bei und transformiert die Money-Management-Blöcke in StockSharp-Idiome.

Handelslogik

  1. Band-Squeeze und Ausdehnung
    • Bollinger Bands (Länge 20, Abweichung 2 standardmäßig) werden auf dem Arbeits-Zeitrahmen berechnet.
    • Die Breite der zuletzt abgeschlossenen Kerze wird gegen die Breite RetraceCandles Bars zuvor verglichen.
    • Ein gültiger Ausbruch erfordert, dass die Breitenverhältnis SqueezeRatio übersteigt, was signalisiert, dass der Preis aus dem Squeeze herausexpandiert.
  2. Trendfilter
    • Zwei gewichtete gleitende Durchschnitte (WMA 6 und WMA 85 auf Typical Price) definieren den sofortigen Trend. Long-Trades erfordern, dass der schnelle WMA über dem langsamen WMA liegt, Shorts das Gegenteil.
  3. Momentum-Bestätigung
    • Ein höherzeitiger Momentum-Indikator (Länge 14) prüft, ob der Preis ausreichend vom 100-Niveau abweicht. Die maximale Abweichung der letzten drei höherzeitigen Werte muss den richtungsspezifischen Schwellenwert überschreiten.
    • Der höhere Zeitrahmen wird automatisch ausgewählt, um das im MT4-Skript verwendete Mapping zu entsprechen (z.B. M15 → H1, H1 → D1, D1 → monatlich). Wochendaten fallen auch auf monatliche Bestätigung zurück. Wenn kein höherer Zeitrahmen verfügbar ist, wird der Momentum-Filter übersprungen.
  4. Makro-Filter
    • Ein monatliches MACD (12/26/9) stellt sicher, dass längerfristiges Momentum mit der Handelsrichtung übereinstimmt (MACD-Linie über Signal für Longs, darunter für Shorts).
  5. Einstiegsregeln
    • Longs: Band-Ausdehnung, schneller WMA über langsamem WMA, monatlicher MACD bullisch, höherzeitiger Momentum-Abweichung über MomentumBuyThreshold, und struktureller Kerzen-Überlapp (candle[-2].Low < candle[-1].High).
    • Shorts: Band-Ausdehnung, schneller WMA unter langsamem WMA, monatlicher MACD bärisch, Momentum-Abweichung über MomentumSellThreshold, und gespiegelte Kerzenbedingung (candle[-1].Low < candle[-2].High).
  6. Ausstiegsregeln
    • Positionen werden geschlossen, wenn der Preis am äußeren Bollinger Band in der Handelsrichtung schließt oder darüber hinausgeht (d.h. Long-Ausstiege am oberen Band, Short-Ausstiege am unteren Band), entsprechend der MT4-Implementierung.
    • StartProtection() aktiviert StockSharp's Schutzorder-Infrastruktur, sodass Stop-Loss/Take-Profit-Erweiterungen bei Bedarf hinzugefügt werden können.

Indikatoren und Daten-Abonnements

  • Primäre Zeitrahmen-Kerzen definiert durch CandleType.
  • Höhere Zeitrahmen-Kerzen für Momentum-Bestätigung (automatisch vom Basis-Zeitrahmen gemappt).
  • Monatliche Kerzen für MACD-Filterung (30-Tage-Approximation).
  • Indikatoren: Bollinger Bands, zwei gewichtete gleitende Durchschnitte (Typical Price), Momentum und MovingAverageConvergenceDivergenceSignal.

Parameter

Name Standard Beschreibung
CandleType 15-Minuten-Kerzen Primärer Arbeits-Zeitrahmen.
BollingerPeriod 20 Bollinger Band-Länge.
BollingerWidth 2.0 Bollinger Band-Standardabweichungs-Multiplikator.
SqueezeRatio 1.1 Minimales Breitenausdehnungsverhältnis zwischen aktuellen und historischen Bändern.
RetraceCandles 10 Rückblick für Squeeze-Vergleich.
FastMaLength 6 Länge des schnellen WMA (Typical Price).
SlowMaLength 85 Länge des langsamen WMA (Typical Price).
MomentumLength 14 Momentum-Periode im höheren Zeitrahmen.
MomentumBuyThreshold 0.3 Minimale Abweichung von 100 zur Validierung von Long-Einstiegen.
MomentumSellThreshold 0.3 Minimale Abweichung von 100 zur Validierung von Short-Einstiegen.

Alle Parameter sind als StrategyParam<T>-Werte exponiert und können in StockSharp Designer oder zur Laufzeit optimiert werden.

Implementierungshinweise

  • Die Strategie verwendet SubscribeCandles().BindEx(...), um das Indikator-Wiring deklarativ zu halten und manuelle Indikator-Sammlungen zu vermeiden, wie von den High-Level-API-Richtlinien verlangt.
  • Gewichtete gleitende Durchschnitte werden durch Typical Price innerhalb des Kerzenverarbeitungs-Callbacks angetrieben, um das Verhalten der LWMA-Berechnungen im MT4-Skript zu bewahren.
  • Höherzeitige Momentum-Werte werden in einer Drei-Element-Queue gespeichert, um iMomentum-Rückblicke 1–3 aus dem Originalcode zu imitieren.
  • Monatliche MACD-Werte persistieren in Klassen-Feldern, damit jede primäre Zeitrahmen-Kerze Zugriff auf den neuesten Langzeit-Bias hat.
  • Ausstiege, die durch die äußeren Bänder ausgelöst werden, ersetzen die MT4-Trailing-Stop/Break-Even-Blöcke, behalten aber die visuelle Absicht des Schließens bei, wenn der Preis die entgegengesetzte Hülle berührt.
  • Die Strategie überlässt die Ordergrößenbestimmung dem Basis-Strategy.Volume. Positionsflips kompensieren automatisch jede bestehende Exponierung, indem Math.Abs(Position) zum Ordervolumen hinzugefügt wird.
using System;
using System.Collections.Generic;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class BollingerBandSqueezeBreakoutStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private decimal? _prevFast, _prevSlow;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }

	public BollingerBandSqueezeBreakoutStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame()).SetDisplay("Candle Type", "Timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 10).SetGreaterThanZero().SetDisplay("Fast EMA", "Fast EMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 30).SetGreaterThanZero().SetDisplay("Slow EMA", "Slow EMA period", "Indicators");
	}

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

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = null;
		_prevSlow = null;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevFast = null; _prevSlow = null;
		var fast = new ExponentialMovingAverage { Length = FastPeriod };
		var slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, ProcessCandle).Start();
		var area = CreateChartArea();
		if (area != null) { DrawCandles(area, subscription); DrawIndicator(area, fast); DrawIndicator(area, slow); DrawOwnTrades(area); }
	}

	private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) { _prevFast = fast; _prevSlow = slow; return; }
		if (_prevFast == null || _prevSlow == null) { _prevFast = fast; _prevSlow = slow; return; }
		var prevAbove = _prevFast.Value > _prevSlow.Value;
		var currAbove = fast > slow;
		_prevFast = fast; _prevSlow = slow;
		if (!prevAbove && currAbove && Position <= 0) { if (Position < 0) BuyMarket(); BuyMarket(); }
		else if (prevAbove && !currAbove && Position >= 0) { if (Position > 0) SellMarket(); SellMarket(); }
	}
}