Auf GitHub ansehen

Exp BlauHlm-Strategie

Übersicht

Die Exp BlauHlm-Strategie ist ein StockSharp-Port des MetaTrader 5-Expertenberaters Exp_BlauHLM.mq5. Das System basiert auf dem Blau High-Low Momentum (HLM)-Oszillator, der aktuelle Hochs und Tiefs vergleicht, die Differenz mit einer konfigurierbaren XMA-Pipeline glättet und auf drei diskrete Betriebsmodi reagiert:

  • Breakdown – handelt einen Null-Linien-Durchbruch der Histogrammkomponente.
  • Twist – sucht nach Momentumdrehungen innerhalb des Histogramms, um Neigungsübergänge zu erfassen.
  • CloudTwist – arbeitet mit den oberen und unteren Hüllen des Indikators und reagiert auf „Wolken"-Kreuzungen.

Die StockSharp-Implementierung behält dieselben Parameter, Standardwerte und Handelsregeln bei und übersetzt Geldmanagement-Spezifika in die generische Volume-Eigenschaft der Basisstrategie.

Handelslogik

  1. Für jede abgeschlossene Kerze des konfigurierten Zeitrahmens berechnet die Strategie den Blau HLM-Oszillator:
    • Die Differenz zwischen dem neuesten Hoch und dem Hoch XLength - 1 Bars zurück und eine gespiegelte Differenz für Tiefs berechnen.
    • Negative Beiträge auf null begrenzen und subtrahieren, um den rohen HLM-Wert zu erhalten (in Punkten ausgedrückt wenn das Instrument eine Tick-Größe angibt).
    • Die Sequenz durch vier kaskadierte gleitende Durchschnitte mit identischen Methoden aber unabhängigen Längen glätten.
  2. Abhängig vom gewählten Mode:
    • Breakdown öffnet eine Long-Position wenn der ältere Histogrammwert positiv und der neuere nicht positiv ist (Null-Linien-Erholung) und schließt Shorts in der gleichen Situation. Eine symmetrische Regel behandelt Short-Einstiege/Long-Ausstiege wenn das Histogramm von negativ auf nicht negativ wechselt.
    • Twist vergleicht die Histogrammneigung über drei historische Punkte. Eine lokale Beschleunigung (mittlerer Wert steigt nach einem Rückgang) löst Long-Logik aus, während eine Verlangsamung (mittlerer Wert fällt nach einem Anstieg) Short-Logik aktiviert.
    • CloudTwist überwacht die zwei geglätteten Hüllen. Wenn das ältere obere Band über dem unteren liegt und die neueren Werte sich unter-/übereinander kreuzen, werden Long- oder Short-Signale entsprechend erzeugt.
  3. Das Positionsmanagement folgt den Berechtigungen BuyOpen, SellOpen, BuyClose, SellClose und verwendet Volume der Strategie für Markteinstiege. Entgegengesetzte Signale schließen bestehende Positionen bevor eine neue eröffnet wird.

Parameter

Name Typ Standard Beschreibung
CandleType DataType H4-Kerzen Vom Oszillator verarbeiteter Zeitrahmen.
SmoothingMethod SmoothMethod Exponential Gleitender-Durchschnitt-Methode für jede Glättungsstufe (nicht unterstützte Legacy-Modi fallen auf EMA zurück).
XLength int 2 Spanne in Bars für das rohe Hoch/Tief-Momentum.
FirstLength int 20 Periode der ersten Glättungsstufe.
SecondLength int 5 Periode der zweiten Glättungsstufe.
ThirdLength int 3 Periode der dritten Glättungsstufe.
FourthLength int 3 Periode des finalen Signal-Glätters.
Phase int 15 Jurik-Phase-Parameter (begrenzt auf ±100, von Nicht-Jurik-Glättern ignoriert).
SignalBar int 1 Historischer Versatz beim Vergleich von Indikatorwerten.
EntryMode Mode Twist Aus dem MQL-Experten kopierte Handelslogik (Breakdown, Twist, CloudTwist).
BuyOpen / SellOpen bool true Long/Short-Positionen nach einem Signal eröffnen erlauben.
BuyClose / SellClose bool true Long/Short-Positionen bei entgegengesetztem Signal schließen erlauben.

Konvertierungshinweise

  • Die MQL-Bibliothek SmoothAlgorithms.mqh enthält proprietäre Filter (JJMA, JurX, ParMA, T3, VIDYA, AMA). StockSharp bietet integrierte Alternativen für die gängigsten Varianten, daher werden nicht unterstützte Modi mit dem exponentiellen gleitenden Durchschnitt approximiert, um den Workflow intakt zu halten.
  • Geldmanagement-Parameter (MM, MarginMode, StopLoss, TakeProfit, Deviation) steuern Ordergröße und Ausführung in MetaTrader. In diesem Port definiert die generische Volume-Eigenschaft die Positionsgröße und Orders werden immer zum Marktpreis gesendet.
  • Das Signal-Timing spiegelt den SignalBar-Versatz des ursprünglichen Experten wider: Die Strategie pflegt einen internen Ringpuffer mit Indikatorwerten und vergleicht historische Snapshots, damit Optimierungsergebnisse konsistent bleiben.
  • Der Risikoschutz wird an StartProtection() delegiert; globale Stop-Loss/Take-Profit-Regeln bei der übergeordneten Strategie oder dem Trading-Connector konfigurieren, falls erforderlich.

Verwendungstipps

  1. Die Volume-Eigenschaft vor dem Start der Strategie setzen, um die Anzahl der Lots/Kontrakte pro Trade festzulegen.
  2. Für Symbole ohne sinnvollen PriceStep arbeitet der Oszillator in rohen Preiseinheiten. Parameter ggf. neu skalieren wenn der Basiswert große Tick-Größen verwendet.
  3. Bei Experimenten mit nicht-exponentiellen Glättern beachten, dass sehr kurze Längen kombiniert mit Jurik-Phase-Extremen zu unruhigen Signalen führen können; Perioden verbreitern für mehr Stabilität.
  4. Strategie mit portfolioweiten Risikokontrollen oder den integrierten Schutzregeln kombinieren, um das ursprüngliche Stop-Loss/Take-Profit-Verhalten zu emulieren.
using System;
using System.Collections.Generic;

using Ecng.Common;

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

namespace StockSharp.Samples.Strategies;

public class ExpBlauHlmStrategy : Strategy
{
	private readonly StrategyParam<int> _fastPeriod;
	private readonly StrategyParam<int> _slowPeriod;
	private readonly StrategyParam<int> _stopLossPoints;
	private readonly StrategyParam<int> _takeProfitPoints;

	private ExponentialMovingAverage _fast;
	private ExponentialMovingAverage _slow;

	private decimal _prevFast;
	private decimal _prevSlow;
	private decimal _entryPrice;
	private int _cooldown;

	public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
	public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
	public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
	public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }

	public ExpBlauHlmStrategy()
	{
		_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
		_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
		_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
		_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
	}

	public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
	{
		yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
	}

	protected override void OnReseted()
	{
		base.OnReseted();
		_fast = null; _slow = null;
		_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
	}

	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_fast = new ExponentialMovingAverage { Length = FastPeriod };
		_slow = new ExponentialMovingAverage { Length = SlowPeriod };
		var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
		subscription.Bind(_fast, _slow, ProcessCandle);
		subscription.Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
		if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }

		var close = candle.ClosePrice;
		var step = Security?.PriceStep ?? 1m;

		if (Position > 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}
		else if (Position < 0 && _entryPrice > 0)
		{
			if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
			if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
		}

		if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
		{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
		else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
		{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }

		_prevFast = fastValue; _prevSlow = slowValue;
	}
}