Auf GitHub ansehen

FX-CHAOS Scalp MT4-Strategie

Überblick

Die FX-CHAOS Scalp MT4-Strategie ist eine direkte Portierung des Expert Advisors MetaTrader 4, der einen Awesome Oscillator-Filter mit auf Fraktalen basierenden ZigZag-Levels kombiniert. Die StockSharp-Version behält das Multi-Timeframe-Design des ursprünglichen Systems bei: Stündliche Kerzen erzeugen Handelssignale, während tägliche Kerzen eine stärkere Zeitrahmen-Tendenz bieten. Zwei eingebettete Tracker rekonstruieren den Indikator „ZigZag on Fractals“, indem sie Fünf-Kerzen-Muster scannen und abwechselnde Swing-Hochs und -Tiefs aufzeichnen.

Handelsablauf

  1. Datenerfassung
    • Stündliche Kerzen versorgen die primäre Ausführungslogik und Risikokontrolle.
    • Tägliche Kerzen aktualisieren den als Trendfilter verwendeten langfristigen ZigZag-Swing.
    • Der Awesome Oscillator (5, 34) wird in der stündlichen Reihe durch den High-Level-Indikator API bewertet.
  2. Zick-Zack-Rekonstruktion
    • Jede fertige Kerze wird in einem verschiebbaren Fenster mit fünf Elementen aufbewahrt.
    • Wenn die mittlere Kerze ein Aufwärts-Fraktal bildet, speichert der Tracker das Hoch der Kerze als letzten Schwung und ändert die Richtung auf „Aufwärts“. Ein Down-Fraktal bewirkt dasselbe für Tiefs.
    • Aufeinanderfolgende Schwankungen in die gleiche Richtung werden nur dann ersetzt, wenn das neue Extrem ausgeprägter ist, was die Pufferlogik des MT4-Indikators nachahmt.
  3. Signalerkennung
    • Der Breakout-Puffer fügt zwei Preisschritt-Offsets zum Hoch/Tief der vorherigen Stunde hinzu und spiegelt die 2*Point-Auffüllung im Originalcode wider.
    • Bei Long-Einstiegen muss die Kerze unterhalb des gepufferten Hochs öffnen, darüber schließen, unter dem letzten stündlichen ZigZag-Schwung bleiben, über dem letzten Tagesschwung schließen und den Awesome Oscillator negativ halten.
    • Kurze Einträge spiegeln die Bedingungen unter Verwendung der gepufferten niedrigen, oberen ZigZag-Ebene und positiven Oszillatorwerte wider.
  4. Auftragsausführung und Konfliktlösung
    • Gegensätzliche Positionen werden geschlossen, bevor ein neuer Auftrag gesendet wird, sodass die Strategie niemals gleichzeitige Long- und Short-Trades vorsieht.
    • Der ausgeführte Schlusskurs wird gespeichert, um Stop-Loss- und Take-Profit-Abstände bei nachfolgenden Kerzen abzuleiten.

Risikomanagement

  • Stop-Loss- und Take-Profit-Schwellenwerte sind optional; ein Wert von 0 deaktiviert die entsprechende Regel.
  • Am Ende jeder fertigen Kerze prüft die Strategie, ob die Kerzenspanne den konfigurierten Stopp oder das konfigurierte Ziel berührt hat und schließt die Position, wenn das Niveau durchbrochen wurde.
  • Wenn ein entgegengesetzter Ausbruch auftritt, wird die Position zuerst liquidiert, dann wird der neue Handel auf derselben Kerze gesendet, um die Einzelpositionsregel beizubehalten.

Parameter

Name Beschreibung
Volume Handelsvolumen in Lots, angewendet auf jede Marktorder.
Stop Loss (pts) Abstand in Punkten für den Schutzstopp. Multipliziert mit der Wertpapierpreisstufe. Zum Deaktivieren auf 0 setzen.
Take Profit (pts) Abstand in Punkten für das Gewinnziel. Multipliziert mit der Preisstufe. Zum Deaktivieren auf 0 setzen.
Breakout Buffer Zusätzliche Punkte, die zum vorherigen Kerzenextremum hinzugefügt wurden, bevor Ausbrüche getestet wurden. Der Standardwert reproduziert das in MT4 verwendete Polster 2*Point.
Spread (pts) Durchschnittlicher Spread in Punkten, der bei Kaufsignalen zur Ausbruchsschwelle addiert wird, sodass der Einstieg 2*Point + spread von MT4 widerspiegelt.
Trading Candle Primärer Zeitrahmen für Einträge (standardmäßig eine Stunde).
Daily Candle Für den ZigZag-Filter wird ein höherer Zeitrahmen verwendet (standardmäßig ein Tag).

Implementierungshinweise

  • Die Strategie basiert auf den übergeordneten SubscribeCandles API und BindEx, um die direkte Arbeit mit Indikatorpuffern zu vermeiden und dabei die Repository-Richtlinien zu respektieren.
  • Der von Security.PriceStep abgerufene Preisschritt wird verwendet, um in Punkten ausgedrückte Parameterwerte in absolute Preisabstände umzuwandeln. Wenn dem Instrument ein Schritt fehlt, fällt der Code auf 1 zurück.
  • Beide ZigZag-Tracker werden am OnReseted zurückgesetzt und unterbrechen den Handel, bis sie genügend Kerzen angesammelt haben, um den ersten Schwung zu bestimmen. Dies verhindert vorzeitige Einträge, wenn historischer Kontext fehlt.
  • Bei der Diagrammdarstellung werden die stündlichen Kerzen, der Awesome Oscillator und die Strategie-Trades gezeichnet, um den Vergleich der StockSharp-Implementierung mit der MT4-Vorlage zu erleichtern.
using System;

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

namespace StockSharp.Samples.Strategies;

public class FxChaosScalpMt4Strategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _momentumPeriod;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevMom;
	private bool _hasPrev;
	private int _cooldownRemaining;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int MomentumPeriod { get => _momentumPeriod.Value; set => _momentumPeriod.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public FxChaosScalpMt4Strategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 14).SetDisplay("EMA Period", "EMA filter", "Indicators");
		_momentumPeriod = Param(nameof(MomentumPeriod), 10).SetDisplay("Momentum", "Momentum period", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 200).SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevMom = default;
		_hasPrev = default;
		_cooldownRemaining = default;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_prevMom = 0;
		_hasPrev = false;
		_cooldownRemaining = 0;

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var mom = new Momentum { Length = MomentumPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, mom, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal ema, decimal mom)
	{
		if (candle.State != CandleStates.Finished) return;
		var close = candle.ClosePrice;
		if (!_hasPrev) { _prevMom = mom; _hasPrev = true; return; }

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			_prevMom = mom;
			return;
		}

		if (close > ema && _prevMom <= 0 && mom > 0 && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (close < ema && _prevMom >= 0 && mom < 0 && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
		_prevMom = mom;
	}
}