Auf GitHub ansehen

Strategie Starter V6 Mod E

Starter V6 Mod E ist eine High-Level-StockSharp-Konvertierung des MetaTrader 4 Expert Advisors Starter_v6mod_e_www_forex-instruments_info.mq4. Der Port behält die ursprüngliche Kombination aus Laguerre-Oszillator-Extremen, dualer EMA-Impulsbestätigung, CCI-Filterung und EMA-Winkel-Gating bei und passt die Ausführung gleichzeitig an die ereignisgesteuerte Architektur von StockSharp an.

Handelslogik

  • Trend-Gate: Eine 34-Perioden-EMA-Steigung wird zwischen konfigurierbaren Start-/Endverschiebungen gemessen. Die Steigung wird in Pip-Einheiten ausgedrückt; Nur positive Steigungen ermöglichen Long-Trades, nur negative Steigungen ermöglichen Short-Positionen und flache Werte blockieren neue Einstiege.
  • Laguerre-Extreme: Ein handgefertigter Laguerre RSI (Gamma = 0,7 standardmäßig) verfolgt überverkaufte/überkaufte Zustände auf der Skala von 0–1. Bei Long-Positionen müssen sowohl der aktuelle als auch der vorherige Wert unter dem Niveau Laguerre Oversold bleiben, bei Short-Positionen müssen beide Werte über Laguerre Overbought liegen.
  • EMA Momentumfilter: 120- und 40-Perioden-EMAs (Medianpreis) müssen bei Long-Positionen steigen und bei Short-Positionen fallen, was dem ursprünglichen MA-Filter entspricht.
  • CCI-Bestätigung: Ein 14-Perioden-CCI muss für Long-Positionen unter -CCI Threshold und für Short-Positionen über +CCI Threshold liegen und den Alpha-Filter von MQL replizieren.
  • Sicherheit am Freitag: Neue Trades werden nach Friday Block Hour blockiert und alle verbleibenden Positionen werden liquidiert, sobald Friday Exit Hour erreicht ist.

Risikomanagement

  • Konfigurierbare Stop-Loss-, Take-Profit- und Trailing-Stop-Abstände (in Pips) emulieren den Geldverwaltungsblock des Experten.
  • Trailing-Stops folgen dem günstigsten Preis nach dem Einstieg und schließen den Handel, wenn das Retracement die konfigurierte Distanz überschreitet.
  • Die manuelle Positionsschließung wird über SellMarket/BuyMarket ausgeführt, wodurch eine hohe API-Konformität gewährleistet wird.

Parameter

Parameter Beschreibung
Volume Auftragsvolumen für jeden Markteintritt.
StopLossPips Schutzstoppabstand in Pips.
TakeProfitPips Gewinnziel in Pips.
TrailingStopPips Trailing-Stop-Distanz in Pips (0 deaktiviert das Trailing).
SlowEmaPeriod Zeitraum des langsamen EMA, berechnet am PRICE_MEDIAN.
FastEmaPeriod Periode des schnellen EMA berechnet am PRICE_MEDIAN.
AngleEmaPeriod EMA Zeitraum, der für den Winkeldetektor verwendet wird.
AngleStartShift / AngleEndShift Zur Berechnung der Steigung EMA verwendete Balkenverschiebungen.
AngleThreshold Mindeststeilheit (in Pip-Einheiten), die erforderlich ist, um den Handel zu ermöglichen.
CciPeriod / CciThreshold Zeitraum und absoluter Schwellenwert für den CCI-Filter.
LaguerreGamma Gamma-Parameter für den Laguerre-Oszillator.
LaguerreOversold / LaguerreOverbought Eintrittsschwellen auf der Laguerre-Skala von 0–1.
CandleType Kerzendatentyp (Standard 1 Minute).
FridayBlockHour / FridayExitHour Stunden (lokale Instrumentenzeit), die die Freitagsrisikolimits steuern.

Konvertierungshinweise

  • Der Laguerre-Oszillator wird direkt aus der ursprünglichen rekursiven Formel implementiert, wobei der Ausgangsbereich 0–1 und die Gammaglättung beibehalten werden.
  • Die Steigung EMA ersetzt den Winkelhelfer MQL, indem Pip-normalisierte Unterschiede zwischen historischen EMA-Punkten berechnet werden.
  • Auf Geldverwaltungsfunktionen wie Equity Cut-off und Grid Stacking wird bewusst verzichtet, da die MT4-Variante, die konvertiert wird, diese standardmäßig deaktiviert hat und StockSharp eine explizite Portfoliokontrolle fördert.
  • Bestellungen werden über BuyMarket/SellMarket gesendet und verlassen sich auf OnNewMyTrade, um die Füllpreise für die abschließende Logik zu verfolgen.
namespace StockSharp.Samples.Strategies;

using System;
using System.Collections.Generic;

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

/// <summary>
/// Starter V6 Mod E strategy using dual EMA crossover with Laguerre RSI filter.
/// Buy when fast EMA crosses above slow EMA and Laguerre is oversold.
/// Sell when fast EMA crosses below slow EMA and Laguerre is overbought.
/// </summary>
public class StarterV6ModEStrategy : Strategy
{
	private readonly StrategyParam<int> _slowEmaPeriod;
	private readonly StrategyParam<int> _fastEmaPeriod;
	private readonly StrategyParam<decimal> _laguerreGamma;
	private readonly StrategyParam<decimal> _laguerreOversold;
	private readonly StrategyParam<decimal> _laguerreOverbought;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _lagL0;
	private decimal _lagL1;
	private decimal _lagL2;
	private decimal _lagL3;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _prevLaguerre;
	private bool _hasPrev;

	public int SlowEmaPeriod
	{
		get => _slowEmaPeriod.Value;
		set => _slowEmaPeriod.Value = value;
	}

	public int FastEmaPeriod
	{
		get => _fastEmaPeriod.Value;
		set => _fastEmaPeriod.Value = value;
	}

	public decimal LaguerreGamma
	{
		get => _laguerreGamma.Value;
		set => _laguerreGamma.Value = value;
	}

	public decimal LaguerreOversold
	{
		get => _laguerreOversold.Value;
		set => _laguerreOversold.Value = value;
	}

	public decimal LaguerreOverbought
	{
		get => _laguerreOverbought.Value;
		set => _laguerreOverbought.Value = value;
	}

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

	public StarterV6ModEStrategy()
	{
		_slowEmaPeriod = Param(nameof(SlowEmaPeriod), 26)
			.SetDisplay("Slow EMA", "Slow EMA period", "Indicators");

		_fastEmaPeriod = Param(nameof(FastEmaPeriod), 12)
			.SetDisplay("Fast EMA", "Fast EMA period", "Indicators");

		_laguerreGamma = Param(nameof(LaguerreGamma), 0.7m)
			.SetDisplay("Laguerre Gamma", "Smoothing factor for Laguerre RSI", "Indicators");

		_laguerreOversold = Param(nameof(LaguerreOversold), 0.5m)
			.SetDisplay("Laguerre Oversold", "Oversold level (0-1)", "Indicators");

		_laguerreOverbought = Param(nameof(LaguerreOverbought), 0.5m)
			.SetDisplay("Laguerre Overbought", "Overbought level (0-1)", "Indicators");

		_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		return [(Security, CandleType)];
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();

		_lagL0 = 0m;
		_lagL1 = 0m;
		_lagL2 = 0m;
		_lagL3 = 0m;
		_prevFast = 0m;
		_prevSlow = 0m;
		_prevLaguerre = 0m;
		_hasPrev = false;
	}

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

		_hasPrev = false;
		_lagL0 = _lagL1 = _lagL2 = _lagL3 = 0m;

		var fastEma = new ExponentialMovingAverage { Length = FastEmaPeriod };
		var slowEma = new ExponentialMovingAverage { Length = SlowEmaPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fastEma, slowEma, ProcessCandle)
			.Start();
	}

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

		var laguerre = CalculateLaguerre(candle.ClosePrice);

		if (!_hasPrev)
		{
			_prevFast = fast;
			_prevSlow = slow;
			_prevLaguerre = laguerre;
			_hasPrev = true;
			return;
		}

		// EMA crossover signals
		var bullishCross = _prevFast <= _prevSlow && fast > slow;
		var bearishCross = _prevFast >= _prevSlow && fast < slow;

		// Long: fast EMA crosses above slow + Laguerre was oversold
		if (Position <= 0 && bullishCross && _prevLaguerre <= LaguerreOversold)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Short: fast EMA crosses below slow + Laguerre was overbought
		else if (Position >= 0 && bearishCross && _prevLaguerre >= LaguerreOverbought)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}

		_prevFast = fast;
		_prevSlow = slow;
		_prevLaguerre = laguerre;
	}

	private decimal CalculateLaguerre(decimal price)
	{
		var gamma = LaguerreGamma;

		var l0Prev = _lagL0;
		var l1Prev = _lagL1;
		var l2Prev = _lagL2;
		var l3Prev = _lagL3;

		_lagL0 = (1m - gamma) * price + gamma * l0Prev;
		_lagL1 = -gamma * _lagL0 + l0Prev + gamma * l1Prev;
		_lagL2 = -gamma * _lagL1 + l1Prev + gamma * l2Prev;
		_lagL3 = -gamma * _lagL2 + l2Prev + gamma * l3Prev;

		decimal cu = 0m;
		decimal cd = 0m;

		if (_lagL0 >= _lagL1) cu = _lagL0 - _lagL1; else cd = _lagL1 - _lagL0;
		if (_lagL1 >= _lagL2) cu += _lagL1 - _lagL2; else cd += _lagL2 - _lagL1;
		if (_lagL2 >= _lagL3) cu += _lagL2 - _lagL3; else cd += _lagL3 - _lagL2;

		var denom = cu + cd;
		return denom == 0m ? 0m : cu / denom;
	}
}