Auf GitHub ansehen

Fibo Arc Momentum-Strategie

Überblick

Diese Strategie ist ein StockSharp-Port des MetaTrader-Expertenberaters "FiboArc" (Ordner MQL/24924). Das originale EA kombiniert mehrere Momentum-Filter mit Fibonacci-Arc-Ausbrüchen. Die StockSharp-Implementierung behält dieselbe Idee bei und passt sie an die High-Level-Kerzen-API an:

  • Zwei linear gewichtete gleitende Durchschnitte (FastMaPeriod, SlowMaPeriod) definieren die Trendrichtung.
  • Ein Momentum-Oszillator, gemessen am neutralen 100-Niveau, filtert schwache Setups heraus.
  • Ein MACD-Histogramm bestätigt die Trendstärke und erkennt frische Kreuzungen.
  • Ein vereinfachter Fibonacci-Arc wird auf jedem Balken unter Verwendung der Eröffnungspreise zweier durch TrendAnchorLength und ArcAnchorLength ausgewählter Ankerkerzen rekonstruiert. Ein Ausbruch durch dieses dynamische Niveau ersetzt die objektbasierten Prüfungen der MetaTrader-Version.

Die Strategie funktioniert mit jedem Symbol/Zeitrahmen-Paar, das von StockSharp unterstützt wird. Alle Berechnungen laufen auf vollständig fertigen Kerzen, um das EA-Verhalten zu spiegeln und Lookahead-Bias zu vermeiden.

Indikatoren und Datenfluss

Die Strategie abonniert einen einzelnen Kerzenstrom, der durch CandleType konfiguriert wird. Jede neue fertige Kerze wird über SubscribeCandles(...).BindEx(...) in folgende Indikatoren eingespeist:

Indikator Zweck Standardeinstellungen
LinearWeightedMovingAverage (schnell) Kurzfristiger Trend und Einstiegs-Timing FastMaPeriod = 6, typischer Preis
LinearWeightedMovingAverage (langsam) Übergeordneter Trendfilter SlowMaPeriod = 85, typischer Preis
Momentum Abstand von 100 dient zur Bestätigung starker Bewegungen MomentumPeriod = 14
MovingAverageConvergenceDivergenceSignal Bestätigt den Trend und erkennt Kreuzungen MacdFastPeriod = 12, MacdSlowPeriod = 26, MacdSignalPeriod = 9

Indikatorausgaben werden als IIndicatorValue-Instanzen empfangen; nur Endwerte werden verarbeitet.

Fibonacci-Arc-Rekonstruktion

MetaTrader zeichnet ein echtes Arc-Objekt und liest dessen Werte mit ObjectGetValueByShift. StockSharp verwendet keine Chart-Objekte, daher wird der Arc numerisch emuliert:

  1. Die Strategie führt eine fortlaufende Liste fertiger Kerzen (_history).
  2. TrendAnchorLength wählt den Index des Basisankers, und ArcAnchorLength wählt den zweiten Anker.
  3. Das Arc-Niveau für die aktuelle Kerze wird als lineare Interpolation zwischen den Ankereröffnungen unter Verwendung von FibonacciRatio (Standard 0.618) berechnet.
  4. Für die Ausbruchserkennung wird die vorherige Kerzeneröffnung mit dem vorherigen Arc-Niveau und die aktuelle Kerzeneröffnung mit dem neu berechneten Niveau verglichen. Ein Kreuz von unten (fibCrossUp) oder von oben (fibCrossDown) recreiert die ursprünglichen EA-Prüfungen.

Handelsregeln

Long-Einstiege

Eine Long-Position wird eröffnet, wenn alle folgenden Bedingungen erfüllt sind:

  1. Der vorherige Balken öffnete unterhalb des vorherigen Arc-Niveaus und der aktuelle Balken öffnet oberhalb des neuen Niveaus (fibCrossUp).
  2. Die schnelle LWMA liegt über der langsamen LWMA (bullishTrend).
  3. Der absolute Abstand zwischen Momentum und 100 beträgt mindestens MomentumThreshold.
  4. Die MACD-Hauptlinie liegt über ihrer Signallinie oder hat gerade nach oben gekreuzt (macdAboveSignal oder macdCrossUp).
  5. Die aktuelle Positionsgröße ist kleiner oder gleich null (kein bestehendes Long-Exposure).

Die Strategie kauft Volume plus den absoluten Wert jedes offenen Short-Exposures, um flach-zu-Long-Übergänge sicherzustellen.

Short-Einstiege

Short-Trades spiegeln die Long-Logik:

  1. fibCrossDown bestätigt einen Ausbruch nach unten.
  2. Die schnelle LWMA liegt unter der langsamen LWMA.
  3. Der Momentum-Abstand übersteigt MomentumThreshold.
  4. MACD liegt unter seiner Signallinie oder kreuzt nach unten.
  5. Kein bestehendes Long-Exposure verbleibt.

Ausstiege

Positionen werden geschlossen, wenn eines der folgenden eintritt:

  • Trend- oder MACD-Bedingungen kippen gegen den Trade.
  • Das entgegengesetzte Fibonacci-Ausbruchssignal erscheint.
  • Das adaptive Stop-Loss- oder Take-Profit-Niveau wird berührt.

Alle Ausstiege werden mit Marktorders ausgeführt, um die Konsistenz mit der MetaTrader-Version zu wahren.

Risikomanagement

Das originale EA bot geldbasierte Stops, Trailing-Logik und Break-Even-Schutz. Die StockSharp-Strategie behält dieselben Funktionen mit transparenten Parametern:

  • StopLossDistance und TakeProfitDistance definieren feste Abstände in Preiseinheiten vom ausgeführten Preis.
  • EnableBreakEven, BreakEvenTrigger und BreakEvenOffset steuern das Verhalten beim Verschieben zum Break-Even.
  • EnableTrailing, TrailingTrigger und TrailingDistance implementieren einen kerzenbasiserten Trailing Stop.

Parameter

Name Beschreibung
CandleType Zeitrahmen (und Aggregationstyp) für alle Berechnungen.
FastMaPeriod, SlowMaPeriod Trenddefinierende LWMA-Längen.
MomentumPeriod, MomentumThreshold Momentum-Filtereinstellungen.
MacdFastPeriod, MacdSlowPeriod, MacdSignalPeriod MACD-Konfiguration.
TrendAnchorLength, ArcAnchorLength, FibonacciRatio Fibonacci-Arc-Rekonstruktionssteuerungen.
StopLossDistance, TakeProfitDistance Anfangliche Stop- und Zielabstände (absolute Preiseinheiten).
EnableBreakEven, BreakEvenTrigger, BreakEvenOffset Break-Even-Logik.
EnableTrailing, TrailingTrigger, TrailingDistance Trailing-Stop-Konfiguration.

Verwendung

  1. Fügen Sie die Strategie einem Wertpapier hinzu und setzen Sie Volume entsprechend der gewünschten Positionsgröße.
  2. Passen Sie optional den Zeitrahmen, die gleitenden Durchschnittslängen und Fibonacci-Einstellungen an den Zielmarkt an.
  3. Starten Sie die Strategie. Alle Entscheidungen basieren auf fertigen Kerzen; Intrabar-Ausführung ist nicht erforderlich.
  4. Überprüfen Sie die integrierten Charting-Helfer für die schnellen/langsamen LWMA- und MACD-Panels, wenn der Host Visualisierung unterstützt.
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;

public class FiboArcMomentumStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public FiboArcMomentumStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}