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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Strategies import Strategy
from StockSharp.Algo.Indicators import AverageTrueRange
class fractal_zig_zag_strategy(Strategy):
def __init__(self):
super(fractal_zig_zag_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(8))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._level = self.Param("Level", 2) \
.SetDisplay("Fractal Depth", "Candles on each side to confirm fractal", "Signals")
self._atr_length = self.Param("AtrLength", 14) \
.SetDisplay("ATR Length", "ATR period for stops", "Indicators")
self._window = []
self._trend = 0 # 1=bearish (last was high), 2=bullish (last was low)
self._prev_trend = 0
self._entry_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@property
def Level(self):
return self._level.Value
@property
def AtrLength(self):
return self._atr_length.Value
def OnStarted2(self, time):
super(fractal_zig_zag_strategy, self).OnStarted2(time)
self._window = []
self._trend = 0
self._prev_trend = 0
self._entry_price = 0.0
self._atr = AverageTrueRange()
self._atr.Length = self.AtrLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._atr, self.ProcessCandle).Start()
def ProcessCandle(self, candle, atr_val):
if candle.State != CandleStates.Finished:
return
av = float(atr_val)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
close = float(candle.ClosePrice)
depth = max(1, self.Level)
window_size = depth * 2 + 1
self._window.append((high, low))
while len(self._window) > window_size:
self._window.pop(0)
# Evaluate fractals
if len(self._window) >= window_size:
center_index = len(self._window) - 1 - depth
center = self._window[center_index]
is_high = True
is_low = True
for i in range(len(self._window)):
if i == center_index:
continue
if self._window[i][0] >= center[0]:
is_high = False
if self._window[i][1] <= center[1]:
is_low = False
if not is_high and not is_low:
break
if is_high:
self._trend = 1
if is_low:
self._trend = 2
if av <= 0 or self._trend == 0:
self._prev_trend = self._trend
return
# Exit management
if self.Position > 0:
if close <= self._entry_price - av * 2.0 or close >= self._entry_price + av * 3.0 or self._trend == 1:
self.SellMarket()
self._entry_price = 0.0
elif self.Position < 0:
if close >= self._entry_price + av * 2.0 or close <= self._entry_price - av * 3.0 or self._trend == 2:
self.BuyMarket()
self._entry_price = 0.0
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_trend = self._trend
return
# Entry on trend change
if self.Position == 0 and self._prev_trend != 0 and self._trend != self._prev_trend:
if self._trend == 2:
self._entry_price = close
self.BuyMarket()
elif self._trend == 1:
self._entry_price = close
self.SellMarket()
self._prev_trend = self._trend
def OnReseted(self):
super(fractal_zig_zag_strategy, self).OnReseted()
self._window = []
self._trend = 0
self._prev_trend = 0
self._entry_price = 0.0
def CreateClone(self):
return fractal_zig_zag_strategy()