Auf GitHub ansehen

Strategie für die Hüllkurvenlimit-Leiter

Die Envelope Limit Ladder Strategy ist eine C#-Portierung des MetaTrader Expert Advisors E_2_12_5min.mq4 (ID 7671). Es baut die ursprüngliche Leiter der Limit-Orders rund um einen EMA-Umschlag auf 5-Minuten-Kerzen neu auf und behält dabei das Multi-Target- und Trailing-Management-Modell des alten Roboters bei.

Konzept

  1. Hüllkurvenfilter – eine gleitende durchschnittliche Hüllkurve (Standardwert EMA 144 mit einer Abweichung von 0,05 %), berechnet auf dem konfigurierbaren Zeitrahmen EnvelopeCandleType, liefert die Mittellinie und die oberen/unteren Bänder.
  2. Signalkerze – Handelssignale werden im CandleType-Abonnement ausgewertet (Standard 5 Minuten). Wenn die vorherige Kerze zwischen der Mittellinie und dem nächsten Band schließt, begrenzt die Strategie die Aufträge auf der Mittellinie.
  3. Auftragsleiter – bis zu drei Kauflimits und drei Verkaufslimits werden gleichzeitig platziert:
    • Einstiegspreis: ausgerichteter Mittellinienwert.
    • Stop-Loss: entgegengesetztes Hüllkurvenband.
    • Take-Profit: Band ± benutzerdefinierte Offsets (standardmäßig 8, 13 und 21 Punkte).
  4. Handelsfenster – ausstehende Aufträge werden nur erstellt, wenn TradingStartHour < Hour < TradingEndHour. Alle verbleibenden Limits werden aufgehoben, sobald die Öffnungszeit TradingEndHour erreicht.
  5. Positionsverwaltung – jede ausgeführte Limit-Order platziert sofort ihre eigene Stop- und Take-Profit-Order. Ein optionaler Trailing-Modus verschiebt den Stop auf den gleitenden Durchschnitt (oder hält ihn auf dem gegenüberliegenden Band), wenn der Preis über die Hülle hinaus ausbricht.

Parameter

Parameter Standard Beschreibung
CandleType 5 Minuten Kerzentyp zur Signalerkennung.
EnvelopeCandleType 5 Minuten Kerzentyp, der zur Berechnung der Hülle verwendet wird. Verwenden Sie einen längeren Zeitrahmen, um die MT4-Eingabe EnvTimeFrame nachzuahmen.
EnvelopePeriod 144 Gleitende durchschnittliche Länge des Umschlags.
MaMethod EMA Methode des gleitenden Durchschnitts (SMA, EMA, SMMA, LWMA).
EnvelopeDeviation 0,05 Umschlagbreite in Prozent (0,05 = 0,05 %).
TradingStartHour 0 Erste Stunde, in der ausstehende Aufträge angezeigt werden können (exklusive Prüfung, entspricht MT4-Verhalten).
TradingEndHour 17 Stunde, in der alle ausstehenden Aufträge entfernt werden (exklusive Obergrenze).
FirstTakeProfitPoints 8 Versatz in Punkten, der über die Hüllkurve hinaus für die erste Leitersprosse hinzugefügt wird.
SecondTakeProfitPoints 13 Versatz in Punkten für die zweite Sprosse.
ThirdTakeProfitPoints 21 Versatz in Punkten für die dritte Sprosse.
UseOppositeEnvelopeTrailing true Hält den Stop auf dem gegenüberliegenden Band (true) oder verfolgt ihn zum gleitenden Durchschnitt (false). Spiegelt das MT4-Flag MaElineTSL wider.
OrderVolume 0,1 Volumen pro ausstehender Bestellung (ersetzt die adaptive Losgröße von MT4).

Verhaltenshinweise

  • Die Strategie verwaltet für jede ausgeführte Limit-Order ein separates Stop/Take-Paar. Ausgänge behindern nicht die übrigen Sprossen der Leiter.
  • Das Trailing wird erst nach einem Ausbruch über die Hülle hinaus aktiviert und verschärft den Stop nur in die profitable Richtung.
  • Wenn EnvelopeCandleType von CandleType abweicht, werden die aktuellsten Umschlagwerte des sekundären Abonnements für Signalkerzen wiederverwendet, was weitgehend der MT4-Umschlagsuche für höhere Zeitrahmen entspricht.
  • Die ursprüngliche MT4-Geldverwaltungsroutine (LotsOptimized) wird durch den expliziten Parameter OrderVolume ersetzt, um den Port innerhalb von StockSharp deterministisch zu halten.

Nutzungstipps

  • Passen Sie den Hüllkurven-Zeitrahmen an die MT4-Eingaben an, um das ursprüngliche Verhalten zu reproduzieren (z. B. EnvelopeCandleType bei 5 Minuten belassen oder je nach Bedarf auf 1 Stunde/4 Stunden wechseln).
  • Setzen Sie UseOppositeEnvelopeTrailing auf false, wenn Sie möchten, dass der Trailing Stop zum gleitenden Durchschnitt und nicht zum entgegengesetzten Band springt, sobald der Preis den Umschlag verlässt.
  • Optimieren Sie die Take-Profit-Offsets und die Umschlagsabweichung gemeinsam. Die Leiterabstände hängen von der durch die Hülle erfassten Volatilität ab.
using System;
using System.Collections.Generic;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// Envelope Limit Ladder strategy - Bollinger band mean reversion.
/// Buys when price touches lower band, sells when it touches upper band.
/// Exits at the middle band.
/// </summary>
public class EnvelopeLimitLadderStrategy : Strategy
{
	private readonly StrategyParam<int> _bbPeriod;
	private readonly StrategyParam<decimal> _bbWidth;
	private readonly StrategyParam<DataType> _candleType;

	public int BbPeriod { get => _bbPeriod.Value; set => _bbPeriod.Value = value; }
	public decimal BbWidth { get => _bbWidth.Value; set => _bbWidth.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public EnvelopeLimitLadderStrategy()
	{
		_bbPeriod = Param(nameof(BbPeriod), 20)
			.SetDisplay("BB Period", "Bollinger bands period", "Indicators");

		_bbWidth = Param(nameof(BbWidth), 1.5m)
			.SetDisplay("BB Width", "Bollinger bands deviation", "Indicators");

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

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities() => [(Security, CandleType)];
	protected override void OnReseted() { base.OnReseted(); }

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

		var bb = new BollingerBands { Length = BbPeriod, Width = BbWidth };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.BindEx(bb, ProcessCandle)
			.Start();
	}

	private void ProcessCandle(ICandleMessage candle, IIndicatorValue value)
	{
		if (candle.State != CandleStates.Finished)
			return;

		if (!value.IsFinal || value.IsEmpty)
			return;

		var bbVal = value as BollingerBandsValue;
		if (bbVal == null)
			return;

		var upper = bbVal.UpBand;
		var lower = bbVal.LowBand;
		var middle = bbVal.MovingAverage;

		if (upper == null || lower == null || middle == null)
			return;

		var close = candle.ClosePrice;

		// Mean reversion: buy at lower band
		if (close < lower.Value && Position <= 0)
		{
			if (Position < 0)
				BuyMarket();
			BuyMarket();
		}
		// Mean reversion: sell at upper band
		else if (close > upper.Value && Position >= 0)
		{
			if (Position > 0)
				SellMarket();
			SellMarket();
		}
		// Exit long at middle
		else if (Position > 0 && close > middle.Value)
		{
			SellMarket();
		}
		// Exit short at middle
		else if (Position < 0 && close < middle.Value)
		{
			BuyMarket();
		}
	}
}