Auf GitHub ansehen

Bollinger Band Two MA ZigZag Strategie

Hybrides Trendfolge-System, das Bollinger Band-Umkehrungen, zwei gleitende Durchschnitte höherer Zeitrahmen und Swing-Punkte eines ZigZag-Detektors kombiniert. Bei jedem Signal werden zwei Positionen eröffnet: eine mit einem berechneten Take-Profit-Ziel und eine zweite "Läufer"-Position, die auf Trailing- und Break-even-Logik basiert.

Details

  • Einstiegskriterien:
    • Long: Die vorherige Kerze schloss oberhalb des vorherigen unteren Bollinger-Bandes, nachdem sie zwei Kerzen zuvor darunter schloss, der aktuelle Schlusskurs liegt ebenfalls über diesem unteren Band, und der Preis liegt oberhalb beider gleitender Durchschnitte höherer Zeitrahmen.
    • Short: Die vorherige Kerze schloss unterhalb des vorherigen oberen Bollinger-Bandes, nachdem sie zwei Kerzen zuvor darüber schloss, der aktuelle Schlusskurs liegt ebenfalls unter diesem oberen Band, und der Preis liegt unterhalb beider gleitender Durchschnitte höherer Zeitrahmen.
  • Positionsmanagement:
    • Pro Signal werden zwei Positionen mit First Volume (mit Take-Profit) und Second Volume (Läufer) eröffnet.
    • Stops sind am jüngsten ZigZag-Swing-Extrem minus/plus Pivot Offset (pts) verankert.
    • Der Break-even-Schutz verschiebt den Stop auf den Einstieg plus einem Offset, sobald der unrealisierte Gewinn Break-even Threshold (pts) + Break-even Offset (pts) überschreitet.
    • Der Trailing Stop bewegt sich, wenn der Preis um Trailing Step (pts) über den bestehenden Stop hinaus vorrückt, und hält dabei einen Abstand von Trailing Stop (pts).
  • Take Profit:
    • Der Take-Profit der ersten Position wird als Prozentsatz (Take Profit %) des Abstands zwischen Einstieg und Stop berechnet.
    • Die Läufer-Position hat kein festes Ziel und wird über Stop, Trailing oder entgegengesetzte Signale beendet.
  • Zusätzliche Logik:
    • Entgegengesetzte Signale schließen sofort alle offenen Positionen in der anderen Richtung, bevor neue Trades eingegangen werden.
    • Die Signalverarbeitung verwendet geschlossene Kerzen; Teildaten werden ignoriert.
  • Standardwerte:
    • First Volume = 0.1
    • Second Volume = 0.1
    • Take Profit % = 50
    • Pivot Offset (pts) = 10
    • Use Break-even Move = true
    • Break-even Offset (pts) = 80
    • Break-even Threshold (pts) = 10
    • Trailing Stop (pts) = 80
    • Trailing Step (pts) = 120
    • Bollinger Period = 20
    • Bollinger Width = 2
    • Base Candle = 1-Stunden-Kerzen
    • MA1 Candle = Tageskerzen
    • MA2 Candle = 4-Stunden-Kerzen
    • MA1 Period = 20
    • MA2 Period = 20
    • ZigZag Depth = 12
    • ZigZag Deviation (pts) = 5
    • ZigZag Backstep = 3
  • Filter:
    • Kategorie: Trendfolge
    • Richtung: Beide
    • Indikatoren: Bollinger Bands, Moving Averages, ZigZag
    • Stops: Ja (Swing-Stop, Break-even, Trailing)
    • Komplexität: Fortgeschritten
    • Zeitrahmen: Multi-Zeitrahmen (1h Basis, Daily + 4h Filter)
    • Saisonalität: Nein
    • Neuronale Netze: Nein
    • Divergenz: Nein
    • Risikolevel: Mittel

Hinweise

  • Die Strategie benötigt Kerzen-Abonnements auf drei verschiedenen Zeitrahmen, um die Filter auszuwerten und Ausstiege zu verwalten.
  • Die Swing-Erkennung approximiert die MetaTrader ZigZag-Logik, indem Mindesttiefe, Abweichung und Backstep-Regeln vor der Aktualisierung der Pivot-Niveaus durchgesetzt werden.
  • Die Volumina können unabhängig voneinander angepasst werden, um das Verhältnis des Take-Profit-Beins zum Läufer-Bein zu optimieren.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Bollinger Band Two MA ZigZag strategy (simplified). Uses EMA crossover
/// with Highest/Lowest channel for swing-based entries.
/// </summary>
public class BollingerBandTwoMaZigZagStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _emaFastLength;
	private readonly StrategyParam<int> _emaSlowLength;
	private readonly StrategyParam<int> _channelLength;

	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	public int EmaFastLength
	{
		get => _emaFastLength.Value;
		set => _emaFastLength.Value = value;
	}

	public int EmaSlowLength
	{
		get => _emaSlowLength.Value;
		set => _emaSlowLength.Value = value;
	}

	public int ChannelLength
	{
		get => _channelLength.Value;
		set => _channelLength.Value = value;
	}

	public BollingerBandTwoMaZigZagStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
			.SetDisplay("Candle Type", "Candles", "General");

		_emaFastLength = Param(nameof(EmaFastLength), 10)
			.SetGreaterThanZero()
			.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");

		_emaSlowLength = Param(nameof(EmaSlowLength), 30)
			.SetGreaterThanZero()
			.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");

		_channelLength = Param(nameof(ChannelLength), 20)
			.SetGreaterThanZero()
			.SetDisplay("Channel Length", "Highest/Lowest lookback", "Indicators");
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
		var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };

		decimal prevFast = 0, prevSlow = 0;
		var hasPrev = false;

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
			{
				if (candle.State != CandleStates.Finished)
					return;

				if (!hasPrev)
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					hasPrev = true;
					return;
				}

				if (!IsFormedAndOnlineAndAllowTrading())
				{
					prevFast = fastVal;
					prevSlow = slowVal;
					return;
				}

				var close = candle.ClosePrice;

				// EMA crossover combined with price confirmation
				var bullishCross = prevFast <= prevSlow && fastVal > slowVal;
				var bearishCross = prevFast >= prevSlow && fastVal < slowVal;

				if (bullishCross && Position <= 0 && close > fastVal)
					BuyMarket();
				else if (bearishCross && Position >= 0 && close < fastVal)
					SellMarket();

				prevFast = fastVal;
				prevSlow = slowVal;
			})
			.Start();

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