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
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.
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.
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
Die Volume-Eigenschaft vor dem Start der Strategie setzen, um die Anzahl der Lots/Kontrakte pro Trade festzulegen.
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.
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.
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;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class exp_blau_hlm_strategy(Strategy):
def __init__(self):
super(exp_blau_hlm_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(exp_blau_hlm_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(exp_blau_hlm_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return exp_blau_hlm_strategy()