Die GlamTrader-Strategie ist eine StockSharp High-Level-API-Konvertierung des MetaTrader-Expertenberaters GlamTrader.mq5. Der ursprüngliche Roboter verbindet einen verschobenen gleitenden Durchschnitt mit dem Laguerre-RSI-Oszillator und dem Awesome Oscillator, um den Momentum zu filtern, bevor eine einzige Marktposition eröffnet wird. Der Port bewahrt den exakten Entscheidungsbaum und die Geldmanagement-Regeln, während Orderausführung, Charting und Risikokontrollen an StockSharp-Konventionen angepasst werden.
Funktionsweise der Strategie
Die durch CandleType definierte Kerzenserie abonnieren (standardmäßig M15). Der ausgewählte Zeitrahmen versorgt jeden Indikator.
Einen konfigurierbaren gleitenden Durchschnitt auf der ausgewählten AppliedPrice-Quelle erstellen und ihn um MaShift Bars verschieben, um den in MetaTrader verwendeten verschobenen Puffer zu reproduzieren.
Den Laguerre-RSI-Filter intern mithilfe des vierstufigen rekursiven Filters nachbilden (LaguerreGamma steuert den Glättungsfaktor). Der Wert bleibt im Bereich [0;1] wie der ursprüngliche benutzerdefinierte Indikator.
Den Awesome Oscillator mit Standard-5/34-einfachen Durchschnitten des Median-Preises berechnen und die aktuellen und vorherigen Messwerte für die Steilheitserkennung speichern.
Nur wenn keine Position offen ist:
Long-Einstieg – gleitender Durchschnitt über dem aktuellen Schlusskurs, Laguerre RSI über 0.15, und Awesome Oscillator steigend im Vergleich zur vorherigen Bar.
Short-Einstieg – gleitender Durchschnitt unter dem aktuellen Schlusskurs, Laguerre RSI unter 0.75, und Awesome Oscillator fallend im Vergleich zur vorherigen Bar.
Beim Einstieg wandelt die Strategie Stop-Loss/Take-Profit-Abstände von Pips in Preisabstände unter Verwendung der Instrument-Tick-Größe um. Abstände werden für 3- oder 5-stellige Kurse genau wie Point * 10 in MQL angepasst.
Während eine Position aktiv ist, spiegelt der Algorithmus die ursprüngliche Trailing-Routine: sobald der Preis mehr als TrailingStopPips + TrailingStepPips voranzieht, wird der Stop auf TrailingStopPips hinter (oder über) dem Markt nachgezogen. Exits werden ausgeführt, wenn der Kerzenrange den Trailing-Stop- oder Take-Profit-Preis berührt.
Einstiegs- und Ausstiegslogik
Immer höchstens eine Position halten. Entgegengesetzte Signale werden ignoriert, bis der aktuelle Trade geschlossen ist.
Long-Trades erfordern einen bearischen verschobenen gleitenden Durchschnitt (Preis kreuzt über die Linie), Laguerre RSI verlässt die überverkaufte Zone (> 0.15), und zunehmendes Awesome Oscillator-Momentum.
Short-Trades erfordern einen bullischen verschobenen gleitenden Durchschnitt (Preis kreuzt unter die Linie), Laguerre RSI fällt aus der überkauften Zone (< 0.75), und abnehmendes Awesome Oscillator-Momentum.
Stops und Ziele werden durch Preisvergleiche gegen Kerzenhochs/-tiefs durchgesetzt, so dass Intrabar-Treffer respektiert werden, obwohl die Logik auf abgeschlossenen Kerzen läuft.
Trailing folgt der MetaTrader-Regel: der Stop bewegt sich nur, nachdem der Preis um den Stop-Abstand plus den Trailing-Schritt voranzieht, und kehrt nie zurück.
Parameter
Parameter
Typ
Standard
Beschreibung
CandleType
DataType
TimeSpan.FromMinutes(15).TimeFrame()
Zeitrahmen für Indikatorberechnungen und Entscheidungsfindung.
TradeVolume
decimal
1
Volumen für Marktorders.
StopLossBuyPips
decimal
50
Stop-Loss-Abstand in Pips für Long-Einstiege.
TakeProfitBuyPips
decimal
50
Take-Profit-Abstand in Pips für Long-Einstiege.
StopLossSellPips
decimal
50
Stop-Loss-Abstand in Pips für Short-Einstiege.
TakeProfitSellPips
decimal
50
Take-Profit-Abstand in Pips für Short-Einstiege.
TrailingStopPips
decimal
5
Trailing-Stop-Abstand in Pips. Auf null setzen um Trailing zu deaktivieren.
TrailingStepPips
decimal
15
Zusätzlicher Gewinn (in Pips) erforderlich bevor der Trailing-Stop sich bewegen kann.
MaPeriod
int
14
Lookback-Länge des gleitenden Durchschnitts.
MaShift
int
1
Positive Verschiebung auf den gleitenden Durchschnitt angewendet.
MaMethod
MaMethod
LinearWeighted
Typ des gleitenden Durchschnitts (einfach, exponentiell, geglättet oder linear gewichtet).
AppliedPrice
AppliedPrice
Weighted
Preisquelle für gleitenden Durchschnitt und Laguerre-Filter.
LaguerreGamma
decimal
0.7
Laguerre-Glättungskoeffizient (Bereich 0–1).
Verwendungshinweise
Die Strategie an das gewünschte Wertpapier anhängen, sicherstellen, dass das Broker-Modell Tick-Größen-/Schrittinformationen liefert, und CandleType auf den gewünschten Zeitrahmen einstellen.
Pip-basierte Risikoparameter an die Instrumentvolatilität anpassen. Die Konvertierung normalisiert Abstände automatisch mit PriceStep; fünfstellige FX-Symbole erhalten den erwarteten 10×-Multiplikator.
Optionale Chart-Helfer zeichnen den gleitenden Durchschnitt im Preisbereich und tragen den Awesome Oscillator in einem separaten Panel zusammen mit den Trades ein.
Die Strategie starten. Sie verwaltet Stops und Trailing intern und spiegelt die OpenBuy-, OpenSell- und Trailing-Routinen aus dem ursprünglichen MQL-Code.
Hinweise
Die Laguerre-RSI-Implementierung spiegelt den laguerre.mq5-Indikator, einschließlich der CU/(CU+CD)-Normalisierung.
Awesome Oscillator-Werte kommen aus StockSharp's eingebautem Indikator, daher ist kein manuelles Puffer-Kopieren erforderlich.
Da die Logik auf abgeschlossenen Kerzen ausgewertet wird, bleiben Backtests und Live-Trading deterministisch und frei von Tick-Level-Repainting.
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;
/// <summary>
/// GlamTrader strategy using EMA crossover with momentum confirmation.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class GlamTraderStrategy : 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;
/// <summary>
/// Fast EMA period.
/// </summary>
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period.
/// </summary>
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
/// <summary>
/// Stop-loss distance in price steps.
/// </summary>
public int StopLossPoints
{
get => _stopLossPoints.Value;
set => _stopLossPoints.Value = value;
}
/// <summary>
/// Take-profit distance in price steps.
/// </summary>
public int TakeProfitPoints
{
get => _takeProfitPoints.Value;
set => _takeProfitPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="GlamTraderStrategy"/> class.
/// </summary>
public GlamTraderStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 25)
.SetGreaterThanZero()
.SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 100)
.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");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_fast = null;
_slow = null;
_prevFast = 0;
_prevSlow = 0;
_entryPrice = 0;
_cooldown = 0;
}
/// <inheritdoc />
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;
// Check SL/TP
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step)
{
SellMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step)
{
BuyMarket();
_entryPrice = 0;
_cooldown = 80;
_prevFast = fastValue;
_prevSlow = slowValue;
return;
}
}
// EMA crossover
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
_entryPrice = close;
_cooldown = 80;
}
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
_entryPrice = close;
_cooldown = 80;
}
_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 glam_trader_strategy(Strategy):
def __init__(self):
super(glam_trader_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 25) \
.SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 100) \
.SetDisplay("Slow Period", "Slow EMA 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(glam_trader_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(glam_trader_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 = 80
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 = 80
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 = 80
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 = 80
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 = 80
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 = 80
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return glam_trader_strategy()