Auf GitHub ansehen

Strategie FXF Safe Trend Scalp V1 (C#)

Die FXF Safe Trend Scalp V1-Strategie handelt Ausbrüche von ZigZag-basierten Trendlinien und spiegelt das Verhalten des ursprünglichen Expertenberaters MetaTrader 4 wider. Es beobachtet den Abstand zwischen dem aktuellen Preis und dynamischen Widerstands-/Unterstützungslinien, die aus aktuellen ZigZag-Pivots erstellt wurden, und gleicht Trades mit einem Paar einfacher gleitender Durchschnitte aus. Schützender Stop-Loss, Take-Profit und ein Floating-Profit-Ausstieg reproduzieren die Geldverwaltungsregeln aus dem Quellcode.

Handelslogik

  1. Zickzack-Trendlinien
    • Ein manueller ZigZag-Detektor sucht anhand der konfigurierbaren Tiefen-, Abweichungs- und Backstep-Parameter nach abwechselnden Schwunghochs und -tiefs.
    • Die letzten vier Swing-Hochs definieren die aktive Widerstandslinie, während die letzten vier Swing-Tiefs die aktive Unterstützungslinie definieren. Die Strategie extrapoliert diese Linien kontinuierlich in den aktuellen Balken.
    • Ein Einstiegssignal wird vorbereitet, wenn sich der Schlusskurs einer Linie innerhalb eines festen Offsets (standardmäßig 10 Punkte) nähert.
  2. Filter für gleitenden Durchschnitt
    • Ein schneller einfacher gleitender Durchschnitt (Länge 2) und ein langsamer einfacher gleitender Durchschnitt (Länge 50) filtern den Trend.
    • Short-Positionen erfordern einen schnellen MA unterhalb des langsamen MA, während Long-Positionen einen schnellen MA oberhalb des langsamen MA erfordern.
  3. Auftragsausführung
    • Signale werden gespeichert und bei der nächsten fertigen Kerze aktiviert, entsprechend der „Neuer Balken“-Logik der MetaTrader-Version.
    • Bevor eine Position eröffnet wird, überprüft die Strategie, ob der Spread das konfigurierte Maximum nicht überschreitet und dass derzeit keine Position offen ist.
  4. Risikomanagement
    • Stop-Loss- und Take-Profit-Distanzen werden in Punkten ausgedrückt und sofort nach Ausführung der Order angewendet.
    • Ein Floating-Profit-Ziel schließt die Position, sobald der nicht realisierte Gewinn (in Preiseinheiten mal Volumen) die konfigurierte Belohnung pro Lot übersteigt.

Parameter

Name Beschreibung
Candle Type Zeitrahmen, der für die Signalgenerierung verwendet wird.
Volume Mit jedem Eintrag übermitteltes Handelsvolumen.
ZigZag Depth Mindestanzahl von Balken zwischen bestätigten Pivots.
ZigZag Deviation (pts) Minimale Preisbewegung in Punkten, bevor sich die Richtung ändert.
ZigZag Backstep Vor dem Akzeptieren eines entgegengesetzten Pivots sind Barren erforderlich.
Trend Offset (pts) Abstand von der Trendlinie, die ein Signal auslöst.
Fast MA Length Länge des schnellen einfachen gleitenden Durchschnitts.
Slow MA Length Länge des langsamen einfachen gleitenden Durchschnitts.
Max Spread (pts) Maximal zulässiger Spread, ausgedrückt in Punkten.
Stop Loss (pts) Abstand des Schutzstopps, gemessen ab dem Einstiegspreis.
Take Profit (pts) Gewinnzielentfernung gemessen vom Einstiegspreis.
Profit Target per Lot Erforderlicher variabler Gewinn (Preiseinheiten × Volumen), um die Position zu schließen.

Notizen

  • Es wird jeweils nur eine Position besetzt. Signale werden ignoriert, solange ein Trade offen ist.
  • Der Spread-Filter basiert auf den besten Geld-/Briefkursen, daher sollte die Strategie mit einer Datenquelle verbunden sein, die Informationen der Ebene 1 bereitstellt.
  • Die Python-Version der Strategie wird wie gewünscht absichtlich weggelassen.

Dateien

  • CS/FXFSafeTrendScalpV1Strategy.cs – StockSharp Implementierung des Expert Advisors.
namespace StockSharp.Samples.Strategies;

using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;

/// <summary>
/// FXF Safe Trend Scalp V1 strategy: SMA crossover with ATR volatility filter.
/// Enters long when fast SMA crosses above slow SMA and ATR confirms volatility.
/// Enters short when fast SMA crosses below slow SMA.
/// </summary>
public class FxfSafeTrendScalpV1Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<int> _signalCooldownCandles;

	private decimal _prevFast;
	private decimal _prevSlow;
	private bool _hasPrev;
	private int _candlesSinceTrade;

	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public int SignalCooldownCandles { get => _signalCooldownCandles.Value; set => _signalCooldownCandles.Value = value; }

	public FxfSafeTrendScalpV1Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
		_fastPeriod = Param(nameof(FastPeriod), 5)
			.SetGreaterThanZero()
			.SetDisplay("Fast Period", "Fast SMA period", "Indicators");
		_slowPeriod = Param(nameof(SlowPeriod), 20)
			.SetGreaterThanZero()
			.SetDisplay("Slow Period", "Slow SMA period", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetGreaterThanZero()
			.SetDisplay("ATR Period", "ATR period", "Indicators");
		_signalCooldownCandles = Param(nameof(SignalCooldownCandles), 3)
			.SetGreaterThanZero()
			.SetDisplay("Signal Cooldown", "Bars to wait between entries", "Trading");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevFast = 0m;
		_prevSlow = 0m;
		_hasPrev = false;
		_candlesSinceTrade = SignalCooldownCandles;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		_candlesSinceTrade = SignalCooldownCandles;
		var fast = new SimpleMovingAverage { Length = FastPeriod };
		var slow = new SimpleMovingAverage { Length = SlowPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(fast, slow, atr, ProcessCandle).Start();
	}

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

		if (_candlesSinceTrade < SignalCooldownCandles)
			_candlesSinceTrade++;

		if (_hasPrev)
		{
			var close = candle.ClosePrice;
			var longSignal = _prevFast <= _prevSlow && fast > slow && close > slow + atr * 0.25m;
			var shortSignal = _prevFast >= _prevSlow && fast < slow && close < slow - atr * 0.25m;

			if (_candlesSinceTrade >= SignalCooldownCandles)
			{
				if (longSignal && Position <= 0)
				{
					BuyMarket();
					_candlesSinceTrade = 0;
				}
				else if (shortSignal && Position >= 0)
				{
					SellMarket();
					_candlesSinceTrade = 0;
				}
			}
		}

		_prevFast = fast;
		_prevSlow = slow;
		_hasPrev = true;
	}
}