Auf GitHub ansehen

TrueSort 1001-Strategie

TrueSort 1001 ist ein striktes Trendfolgesystem, das den ursprünglichen Expertenberater MQL widerspiegelt. Die Strategie überwacht fünf einfache gleitende Durchschnitte und reagiert nur, wenn sie drei aufeinanderfolgende abgeschlossene Kerzen lang perfekt geordnet bleiben. Ein steigender durchschnittlicher Richtungsindex (ADX) bestätigt die Dynamik, bevor ein Handel eröffnet wird. Sobald die Position auf dem Markt ist, wird sie durch einen adaptiven Trailing Stop geschützt, der in Preisschritten gemessen wird, und der Handel wird geschlossen, sobald die gleitenden Durchschnitte ihre Ausrichtung verlieren.

Logik

Trend- und Momentumfilter

  • Für den ausgewählten Zeitrahmen werden fünf SMAs (standardmäßig 10, 20, 50, 100 und 200 Perioden) berechnet.
  • Bei langen Setups müssen die schnellen SMAs bei jeder der letzten drei abgeschlossenen Kerzen streng über den langsameren liegen: SMA10 > SMA20 > SMA50 > SMA100 > SMA200.
  • Für kurze Setups ist die umgekehrte Reihenfolge für dieselben drei Kerzen erforderlich.
  • ADX mit der Periode AdxPeriod muss über AdxThreshold bleiben und der aktuelle Wert muss höher sein als die vorherige Kerze, um sicherzustellen, dass die Trendstärke zunimmt.

Teilnahmebedingungen

  1. Es ist keine Position offen.
  2. Drei historische Kerzen erfüllen die oben beschriebene Ordnungsregel.
  3. Der ADX-Filter ist erfolgreich.
  4. Eine Marktorder von Volume Lots wird sofort beim Schließen der aktuellen Kerze gesendet.

Ausstiegsbedingungen

  • Desynchronisierung des gleitenden Durchschnitts: Wenn die aktuelle Kerze schließt und der MA-Stapel nicht mehr streng in Richtung des Handels geordnet ist, wird die Position liquidiert.
  • Trailing Protection: StopLossPoints werden durch Multiplikation mit dem Instrument PriceStep in den absoluten Preisabstand umgewandelt. Bei Long-Trades wird der Stop auf das Maximum zwischen SMA100 und Close - distance initialisiert. Bei Kurzfilmen liegt der Mindestwert zwischen SMA100 und Close + distance. Nach jeder Kerze wird der Stopp in Richtung des Preises angezogen, aber nie gelockert. Wenn der Preis den Stop überschreitet, wird die Position zum Marktwert geschlossen.

Zusätzliche Hinweise

  • Alle Entscheidungen werden nur für fertige Kerzen getroffen; Unfertige Kerzen werden ignoriert.
  • Der Algorithmus speichert die letzten drei SMA-Werte intern, um die shift-Logik aus dem ursprünglichen MQL-Skript zu replizieren, ohne den Indikatorverlauf anzufordern.
  • ADX-Werte werden über BindEx verarbeitet und der Handel wird nur versucht, wenn die Strategie online ist und die Daten vollständig gebildet sind.

Parameter

Name Standard Beschreibung
Volume 0.1 Bestellgröße in Losen für jeden Markteintritt.
StopLossPoints 100 Trailing-Stop-Distanz, ausgedrückt in Instrumentenpreisschritten. 0 deaktiviert das Trailing.
Sma10Length 10 Zeitraum der schnellsten SMA.
Sma20Length 20 Zeitraum der Sekunde SMA.
Sma50Length 50 Zeitraum des Mediums SMA.
Sma100Length 100 Zeitraum, der sowohl für die Ausrichtung als auch für die anfängliche Stoppreferenz verwendet wird.
Sma200Length 200 Langsamster SMA, der den langfristigen Trend bestätigt.
AdxPeriod 14 Zeitraum des ADX-Indikators.
AdxThreshold 25 Mindestniveau ADX und steigende Bedingung vor Einträgen erforderlich.
CandleType TimeSpan.FromHours(1).TimeFrame() Kerzenreihe, die für alle Indikatorberechnungen verwendet wird.

Details zur Implementierung

  • Der Code basiert auf dem High-Level-Kerzenabonnement StockSharp und bindet sechs Indikatoren (fünf SMAs und ADX) in einer einzigen Pipeline.
  • Verlaufspuffer mit der Länge drei speichern die neuesten SMA-Werte, vermeiden Aufrufe von GetValue() und wahren gleichzeitig die exakte Parität mit den MQL-Verschiebungen.
  • Trailing Stops werden manuell verwaltet; StartProtection() ist weiterhin aktiviert, sodass die Standardinfrastruktur bereit ist, falls weitere Schutzmaßnahmen erforderlich sind.
  • Kommentare im Code erklären jeden Schritt auf Englisch, um die Wartung zu erleichtern.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Trend-following strategy requiring strict moving average alignment
/// and rising volatility (ATR) before entering trades.
/// Exits when alignment is lost.
/// </summary>
public class TrueSort1001Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _fastLength;
	private readonly StrategyParam<int> _midLength;
	private readonly StrategyParam<int> _slowLength;
	private readonly StrategyParam<int> _atrLength;

	private decimal _prevFast;
	private decimal _prevMid;
	private decimal _prevSlow;
	private decimal _prevAtr;
	private decimal _entryPrice;

	public TrueSort1001Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe.", "General");

		_fastLength = Param(nameof(FastLength), 10)
			.SetDisplay("Fast SMA", "Fast SMA period.", "Indicators");

		_midLength = Param(nameof(MidLength), 50)
			.SetDisplay("Mid SMA", "Medium SMA period.", "Indicators");

		_slowLength = Param(nameof(SlowLength), 200)
			.SetDisplay("Slow SMA", "Slow SMA period.", "Indicators");

		_atrLength = Param(nameof(AtrLength), 14)
			.SetDisplay("ATR Length", "ATR period for volatility filter.", "Indicators");
	}

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

	public int FastLength
	{
		get => _fastLength.Value;
		set => _fastLength.Value = value;
	}

	public int MidLength
	{
		get => _midLength.Value;
		set => _midLength.Value = value;
	}

	public int SlowLength
	{
		get => _slowLength.Value;
		set => _slowLength.Value = value;
	}

	public int AtrLength
	{
		get => _atrLength.Value;
		set => _atrLength.Value = value;
	}

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

		_prevFast = 0;
		_prevMid = 0;
		_prevSlow = 0;
		_prevAtr = 0;
		_entryPrice = 0;
	}

		protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevFast = 0;
		_prevMid = 0;
		_prevSlow = 0;
		_prevAtr = 0;
		_entryPrice = 0;

		var fast = new SimpleMovingAverage { Length = FastLength };
		var mid = new SimpleMovingAverage { Length = MidLength };
		var slow = new SimpleMovingAverage { Length = SlowLength };
		var atr = new AverageTrueRange { Length = AtrLength };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(fast, mid, slow, atr, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawIndicator(area, fast);
			DrawIndicator(area, mid);
			DrawIndicator(area, slow);
			DrawOwnTrades(area);
		}
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastVal, decimal midVal, decimal slowVal, decimal atrVal)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (_prevFast == 0 || _prevMid == 0 || _prevSlow == 0)
		{
			_prevFast = fastVal;
			_prevMid = midVal;
			_prevSlow = slowVal;
			_prevAtr = atrVal;
			return;
		}

		var close = candle.ClosePrice;
		var bullishAligned = fastVal > midVal && midVal > slowVal;
		var bearishAligned = fastVal < midVal && midVal < slowVal;
		var atrRising = atrVal > _prevAtr;

		// Exit on alignment lost
		if (Position > 0 && !bullishAligned)
		{
			SellMarket();
		}
		else if (Position < 0 && !bearishAligned)
		{
			BuyMarket();
		}

		// Entry on alignment + rising ATR
		if (Position == 0)
		{
			if (bullishAligned && atrRising && close > fastVal)
			{
				_entryPrice = close;
				BuyMarket();
			}
			else if (bearishAligned && atrRising && close < fastVal)
			{
				_entryPrice = close;
				SellMarket();
			}
		}

		_prevFast = fastVal;
		_prevMid = midVal;
		_prevSlow = slowVal;
		_prevAtr = atrVal;
	}
}