Auf GitHub ansehen

Fraktale Zick-Zack-Strategie

Diese Strategie ist eine direkte Portierung des MetaTrader 4 Expertenberaters Fractal ZigZag Expert.mq4. Es stellt den Gesetzentwurf wieder her Williams fraktale Sequenz und interpretiert das jüngste bestätigte Extremum als den aktiven Marktzweig. Wenn das letzte gültige Fraktal a ist Wenn Sie nach unten schwingen, eröffnet das System eine Long-Position. Wenn ein Swing-Hoch bestätigt wird, wird ein Short eröffnet. Die Implementierung behält die ursprüngliche Parameter – Fraktaltiefe, Take-Profit, Initial-Stop- und Trailing-Stop-Abstände – bei gleichzeitiger Anpassung des Order-Routings an das High-Level StockSharp API.

Die Strategie eignet sich am besten für H1-Kerzen und repliziert das in der MetaTrader-Version verwendete Standarddiagramm. Dennoch ist die Der Parameter CandleType ermöglicht den Wechsel zu jedem anderen vom Datenfeed unterstützten Zeitrahmen. Alle Entfernungen sind im Preis angegeben Punkte (Instrumentenpreisschritte), was die Art und Weise widerspiegelt, wie MetaTrader die Point-Konstante verwendet.

Handelsregeln

  • Signalerkennung
    • Der Algorithmus scannt jede fertige Kerze und erstellt ein rollierendes Fenster mit 2 * Level + 1-Elementen.
    • Ein hohes Fraktal wird bestätigt, wenn die mittlere Kerze innerhalb dieses Fensters das höchste Hoch aufweist; Ein niedriges Fraktal erfordert das niedrigste niedrig.
    • Nur das letzte bestätigte Fraktal bestimmt die Richtung: Ein Tief setzt den internen Trend auf 2 (bullisch), ein Hoch setzt ihn auf 1 (bärisch).
  • Einträge
    • Wenn der interne Trend 2 entspricht und keine offene Position vorhanden ist, wird ein Marktkauf mit dem Volumen Lots gesendet.
    • Wenn der Trend ohne Position gleich 1 ist, wird ein Marktverkauf gesendet.
    • Die Strategie wird in die gleiche Richtung zurückkehren, nachdem eine Position geschlossen wurde, sofern sich der Trend nicht gewendet hat.
  • Exits & Risikomanagement
    • Jeder Eintrag erhält einen anfänglichen Stop-Loss und einen festen Take-Profit, der in Punkten definiert ist. Ein Stoppwert von 0 deaktiviert die entsprechenden Schutz.
    • Der optionale Trailing Stop (auch in Punkten) wird aktiviert, sobald sich der Preis um die konfigurierte Distanz bewegt. Anschließend wird der Anschlag angefahren Behalten Sie den gleichen Abstand zum Schlusskurs bei und überschreiten Sie niemals den anfänglichen Schutzstopp.
    • Schutzaufträge werden nachgeahmt, indem die Kerzenhochs/-tiefs überwacht werden, um Intrabar-Berührungen anzunähern, die dem Original weitgehend entsprechen MQL4-Logik.

Standardparameter

Parameter Standard Beschreibung
Level 2 Anzahl der Kerzen auf jeder Seite, die zur Bestätigung eines Fraktals erforderlich sind.
TakeProfitPoints 25 Abstand zum Take-Profit-Ziel in Preispunkten.
InitialStopPoints 20 Abstand zum anfänglichen Stop-Loss in Preispunkten.
TrailingStopPoints 10 Trailing-Stop-Distanz in Preispunkten (zum Deaktivieren auf 0 setzen).
Lots 1 Für Markteintritte verwendetes Ordervolumen.
CandleType H1 Zeitrahmen der von der Strategie verarbeiteten Kerzen.

Notizen

  • Die Strategie ruft StartProtection() einmal beim Start auf, damit StockSharp bei Bedarf die Liquidation von Notfallpositionen verwalten kann.
  • Alle Protokolle und Kommentare werden auf Englisch bereitgestellt, während Beschreibungen der Sprache jeder README-Variante folgen, wie von der gefordert Konvertierungsrichtlinien.
  • Die Implementierung vermeidet Indikatorpuffer und ahmt den MetaTrader-Ansatz nach, indem nur das minimale rollierende Fenster beibehalten wird notwendig, um ein Fraktal auszuwerten.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Fractal ZigZag: Confirms Bill Williams fractals then trades
/// in the direction of the last confirmed extremum.
/// Bullish after low fractal, bearish after high fractal.
/// </summary>
public class FractalZigZagStrategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _level;
	private readonly StrategyParam<int> _atrLength;

	private readonly List<(decimal high, decimal low, DateTimeOffset time)> _window = new();
	private int _trend; // 1=bearish (last was high), 2=bullish (last was low)
	private int _prevTrend;
	private decimal _entryPrice;

	public FractalZigZagStrategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(8).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_level = Param(nameof(Level), 2)
			.SetDisplay("Fractal Depth", "Candles on each side to confirm fractal.", "Signals");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period for stops.", "Indicators");
	}

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

	public int Level
	{
		get => _level.Value;
		set => _level.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_window.Clear();
		_trend = 0;
		_prevTrend = 0;
		_entryPrice = 0;
	}

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

		var atr = new AverageTrueRange { Length = AtrLength };

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

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

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

		// Update fractal window
		var depth = Math.Max(1, Level);
		var windowSize = depth * 2 + 1;

		_window.Add((candle.HighPrice, candle.LowPrice, candle.OpenTime));
		while (_window.Count > windowSize)
			_window.RemoveAt(0);

		// Evaluate fractals
		if (_window.Count >= windowSize)
		{
			var centerIndex = _window.Count - 1 - depth;
			var center = _window[centerIndex];
			var isHigh = true;
			var isLow = true;

			for (var i = 0; i < _window.Count; i++)
			{
				if (i == centerIndex)
					continue;

				if (_window[i].high >= center.high)
					isHigh = false;
				if (_window[i].low <= center.low)
					isLow = false;

				if (!isHigh && !isLow)
					break;
			}

			if (isHigh)
				_trend = 1; // bearish: last fractal was a high
			if (isLow)
				_trend = 2; // bullish: last fractal was a low
		}

		if (atrVal <= 0 || _trend == 0)
		{
			_prevTrend = _trend;
			return;
		}

		var close = candle.ClosePrice;

		// Exit management
		if (Position > 0)
		{
			if (close <= _entryPrice - atrVal * 2m || close >= _entryPrice + atrVal * 3m || _trend == 1)
			{
				SellMarket();
				_entryPrice = 0;
			}
		}
		else if (Position < 0)
		{
			if (close >= _entryPrice + atrVal * 2m || close <= _entryPrice - atrVal * 3m || _trend == 2)
			{
				BuyMarket();
				_entryPrice = 0;
			}
		}

		// Entry on trend change
		if (Position == 0 && _prevTrend != 0 && _trend != _prevTrend)
		{
			if (_trend == 2)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (_trend == 1)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevTrend = _trend;
	}
}