Auf GitHub ansehen

Lbs V12-Strategie

Überblick

Die Lbs V12-Strategie ist eine Konvertierung des MetaTrader Expert Advisors LBS_V12.mq4. Es öffnet ein Paar Breakout-Stop-Orders rund um die vorherige 15-Minuten-Kerze, wenn die konfigurierte Triggerstunde beginnt. Beide Orders werden durch den aktuellen Average True Range (ATR)-Wert ausgeglichen, um kurzfristige Volatilität zu berücksichtigen. Die Strategie versucht, den ersten Impuls der Handelssitzung zu erfassen und verwaltet Ausstiege durch virtuelle Stop-Loss-, Take-Profit- und Trailing-Regeln, die für jede abgeschlossene Kerze ausgewertet werden.

Handelslogik

  1. Die Strategie überwacht fertige Kerzen des ausgewählten Zeitrahmens (standardmäßig 15 Minuten).
  2. Wenn eine neue Kerze mit der Minute 00 am konfigurierten TriggerHour erscheint, wird die vorherige Kerze zum Referenzbereich.
  3. Wenn für den aktuellen Tag keine offenen Positionen und keine funktionierenden Orders vorhanden sind, werden zwei Stop-Orders gesendet:
    • Kaufstopp über dem Referenzhoch plus dem Instrumenten-Spread, einem Preisschritt und dem letzten ATR-Wert.
    • Verkaufsstopp unterhalb des Referenztiefs abzüglich der gleichen Puffer.
  4. Schutzpreisniveaus für jede Seite werden intern gespeichert:
    • Der Stop-Loss wird jenseits des entgegengesetzten Extrems der Referenzkerze platziert.
    • Der Take-Profit wird anhand der Punktentfernung im MetaTrader-Stil berechnet.
    • Ein Trailing Stop wird aktiviert, sobald sich der Handel weiter als die konfigurierte Distanz bewegt.
  5. Wenn eine Long- oder Short-Position eröffnet wird, wird die entgegengesetzte Stop-Order aufgehoben. Der gesamte Schutz wird virtuell angewendet: Kerzenhochs und -tiefs werden mit den gespeicherten Stop/Take-Werten verglichen und die Position wird mit Marktaufträgen geschlossen, wenn die Limits erreicht sind.
  6. Die Strategie wird nur einmal pro Tag ausgeführt. Alle ausstehenden Aufträge und der interne Status werden zu Beginn eines neuen Handelsdatums gelöscht.

Parameter

Name Beschreibung Standard
Volume Handelsvolumen in Lots. 1
TriggerHour Stunde des Tages (Terminalzeitzone), zu der die Breakout-Orders gesendet werden sollen. 9
TakeProfitPoints MetaTrader-ähnliche Punkte zwischen dem Einstiegspreis und dem Take-Profit-Ziel. 100
TrailingStopPoints Punkte im MetaTrader-Stil, die für den Trailing Stop verwendet werden, nachdem der Trade in die Gewinnzone übergeht. 20
AtrPeriod Zeitraum des Indikators ATR, der die ausstehenden Aufträge ausgleicht. 3
CandleType Kerzentyp, der für Signalberechnungen verwendet wird. Der Standardwert sind Kerzen mit einem Zeitrahmen von 15 Minuten. 15m timeframe

Risikomanagement

  • Ausstiege werden durch Marktaufträge ausgeführt, wenn die Kerzenextreme die virtuellen Stop-Loss- oder Take-Profit-Niveaus berühren.
  • Der Trailing Stop erhöht (für Long-Positionen) oder verringert (für Short-Positionen) das Schutzniveau, wenn der Trade mehr als die konfigurierte Distanz gewinnt.
  • Durch das tägliche Zurücksetzen wird sichergestellt, dass die Strategie nicht mehrere Positionen oder veraltete ausstehende Aufträge ansammelt.

Notizen

  • Genaue Bid/Ask-Aktualisierungen verbessern die Spread-Kompensation, die zu den Breakout-Preisen hinzugefügt wird. Wenn keine Spread-Daten verfügbar sind, fällt die Strategie auf einen Preisschritt zurück.
  • Die Konvertierung behält die ursprünglichen MetaTrader-Standardwerte bei, passt jedoch die Take-Profit-Behandlung für Short-Positionen an, sodass das Ziel immer in die profitable Richtung gelegt wird.
using System;

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

namespace StockSharp.Samples.Strategies;

/// <summary>
/// LBS V12 strategy - ATR channel breakout with EMA trend.
/// Buys when close breaks above EMA + ATR.
/// Sells when close breaks below EMA - ATR.
/// </summary>
public class LbsV12Strategy : Strategy
{
	private readonly StrategyParam<int> _emaPeriod;
	private readonly StrategyParam<int> _atrPeriod;
	private readonly StrategyParam<decimal> _atrMultiplier;
	private readonly StrategyParam<int> _cooldownCandles;
	private readonly StrategyParam<DataType> _candleType;

	private int _cooldownRemaining;

	public int EmaPeriod { get => _emaPeriod.Value; set => _emaPeriod.Value = value; }
	public int AtrPeriod { get => _atrPeriod.Value; set => _atrPeriod.Value = value; }
	public decimal AtrMultiplier { get => _atrMultiplier.Value; set => _atrMultiplier.Value = value; }
	public int CooldownCandles { get => _cooldownCandles.Value; set => _cooldownCandles.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public LbsV12Strategy()
	{
		_emaPeriod = Param(nameof(EmaPeriod), 50)
			.SetDisplay("EMA Period", "EMA lookback", "Indicators");
		_atrPeriod = Param(nameof(AtrPeriod), 14)
			.SetDisplay("ATR Period", "ATR lookback", "Indicators");
		_atrMultiplier = Param(nameof(AtrMultiplier), 3m)
			.SetDisplay("ATR Multiplier", "Channel width multiplier", "Indicators");
		_cooldownCandles = Param(nameof(CooldownCandles), 100)
			.SetDisplay("Cooldown", "Candles between signals", "General");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
			.SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_cooldownRemaining = default;
	}

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

		var ema = new ExponentialMovingAverage { Length = EmaPeriod };
		var atr = new AverageTrueRange { Length = AtrPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(ema, atr, ProcessCandle).Start();
	}

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

		if (_cooldownRemaining > 0)
		{
			_cooldownRemaining--;
			return;
		}

		var close = candle.ClosePrice;
		var mult = AtrMultiplier;

		if (close > ema + atr * mult && Position <= 0)
		{
			if (Position < 0) BuyMarket();
			BuyMarket();
			_cooldownRemaining = CooldownCandles;
		}
		else if (close < ema - atr * mult && Position >= 0)
		{
			if (Position > 0) SellMarket();
			SellMarket();
			_cooldownRemaining = CooldownCandles;
		}
	}
}