Diese Strategie repliziert das Verhalten des MetaTrader-Experten Exp_GStopLoss_Tm und stellt eine Risikoüberlagerung bereit, die das kombinierte Ergebnis aller von der Strategieinstanz eröffneten Trades überwacht. Das Modul generiert selbst keine Einstiegssignale; stattdessen verfolgt es die Gewinne und Verluste bestehender Positionen und erzwingt sowohl einen globalen Stop-Loss-Schwellenwert als auch ein optionales Handelssessionfenster. Wenn die Verluste das konfigurierte Limit überschreiten oder der Markt sich außerhalb des erlaubten Zeitrahmens bewegt, liquidiert die Strategie das aktuelle Exposure und blockiert weitere Trades, bis das Buch wieder ausgeglichen ist.
Handelslogik
Beim Start zeichnet die Strategie den aktuellen realisierten PnL als Basisreferenz auf. Dies ermöglicht es, den schwebenden Gewinn relativ zum zuletzt ausgeglichenen Zustand zu messen.
Jede abgeschlossene Kerze, die vom konfigurierten Kerzentop produziert wird, löst eine Risikoprüfung aus. Der Standard-Zeitrahmen ist eine Minute, um eine Tick-Level-Überwachung zu emulieren, ohne das System zu überlasten.
Das Modul berechnet den unrealisierten Gewinn als Differenz zwischen dem aktuellen Strategie-PnL und dem Basiswert. Positiver PnL wird ignoriert, solange die Strategie innerhalb des Handelsfensters bleibt, entsprechend dem originalen Expert Advisor.
Wenn der Verlustmodus auf Percent gesetzt ist, vergleicht die Strategie den absoluten Verlustprozentsatz mit dem Konto-Eigenkapital aus Portfolio.CurrentValue. Im Currency-Modus erfolgt der Vergleich in absoluten Währungseinheiten.
Sobald der Verlustschwellenwert überschritten ist, wird das Stop-Flag gesetzt und die Strategie beginnt in der nächsten Iteration damit, die offene Position zu schließen. Das Flag wird erst freigegeben, nachdem die Positionsgröße auf null zurückgekehrt ist und der Basis-PnL aktualisiert wurde.
Wenn das optionale Handelsfenster aktiviert ist, prüft die Risikokontrolle auch, ob die Kerzenabschlusszeit innerhalb des erlaubten Intervalls liegt. Das Fenster unterstützt Intraday-Sessions, die über Mitternacht hinausgehen, entsprechend der MetaTrader-Logik.
Wenn das Stop-Flag aktiv ist oder der Session-Filter erkennt, dass der Markt außerhalb der erlaubten Stunden ist, sendet das Modul eine Marktorder in der entgegengesetzten Richtung, um die Position zu glätten. Informative Protokolleinträge beschreiben den Grund für jeden Ausstieg.
Parameter
Name
Beschreibung
LossMode
Legt fest, wie der Verlustschwellenwert interpretiert wird: Prozentsatz des aktuellen Konto-Eigenkapitals oder absolute Kontowährung.
StopLoss
Verlustschwellenwert. Im Prozentmodus repräsentiert die Zahl den Prozentsatz, im Währungsmodus wird die Kontowährung verwendet.
UseTimeFilter
Aktiviert das Intraday-Handelsfenster. Wenn deaktiviert, ignoriert die Strategie den Zeitfilter vollständig.
StartTime
Inklusiver Start des Handelsfensters in UTC. Funktioniert zusammen mit EndTime, um die gültige Session zu definieren.
EndTime
Exklusives Ende des Handelsfensters in UTC. Unterstützt Wrap-Around-Sessions, wenn die Endzeit früher als die Startzeit ist.
CandleType
Kerzen-Abonnement für die periodische Risikobewertung. Standard ist ein 1-Minuten-Zeitrahmen.
Implementierungshinweise
Der Basis-PnL wird neu berechnet, wenn die Positionsgröße auf null zurückkehrt, damit nachfolgende Trades mit einer sauberen Basis beginnen.
Eigenkapitalwerte werden aus dem Live-Portfolio abgerufen, daher passt sich der Prozentmodus sowohl an realisierte als auch unrealisierte Änderungen im Kontowert an.
Alle Kommentare im Quellcode sind wie von den Projektkonventionen gefordert auf Englisch verfasst.
Die Strategie zeichnet Kerzen und eigene Trades im Standard-Diagrammbereich, wenn einer verfügbar ist, um das Verhalten während des Tests zu visualisieren.
Verwendungsrichtlinien
Hängen Sie die Strategie an das Instrument an, das Sie überwachen möchten. Die Ordergenerierung anderer Strategien kann noch stattfinden; dieses Modul überwacht nur und schließt Positionen.
Konfigurieren Sie den Verlustmodus und Schwellenwert entsprechend Ihrem Risikoappetit. Zum Beispiel werden LossMode = Percent und StopLoss = 5 die Position nach einem 5% unrealisierten Drawdown relativ zum aktuellen Eigenkapital schließen.
Setzen Sie die Parameter StartTime und EndTime, um das Trading auf eine bestimmte Intraday-Session zu beschränken. Um ein Übernacht-Fenster abzudecken, geben Sie eine Startzeit an, die später als die Endzeit ist (zum Beispiel 20:00 bis 06:00).
Führen Sie den Backtest oder die Live-Session aus. Die Strategie setzt das Stop-Flag automatisch zurück, sobald alle Positionen ausgeglichen sind, und überwacht dann weiterhin nachfolgende Trades.
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>
/// Global Stop Loss Time strategy (simplified). Trades EMA crossover with
/// session time filter and global stop loss based on drawdown.
/// </summary>
public class GlobalStopLossTimeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _emaFastLength;
private readonly StrategyParam<int> _emaSlowLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int EmaFastLength
{
get => _emaFastLength.Value;
set => _emaFastLength.Value = value;
}
public int EmaSlowLength
{
get => _emaSlowLength.Value;
set => _emaSlowLength.Value = value;
}
public GlobalStopLossTimeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_emaFastLength = Param(nameof(EmaFastLength), 8)
.SetGreaterThanZero()
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators");
_emaSlowLength = Param(nameof(EmaSlowLength), 21)
.SetGreaterThanZero()
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var emaFast = new ExponentialMovingAverage { Length = EmaFastLength };
var emaSlow = new ExponentialMovingAverage { Length = EmaSlowLength };
decimal prevFast = 0, prevSlow = 0;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(emaFast, emaSlow, (ICandleMessage candle, decimal fastVal, decimal slowVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevFast = fastVal;
prevSlow = slowVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevFast = fastVal;
prevSlow = slowVal;
return;
}
// EMA crossover signals
if (prevFast <= prevSlow && fastVal > slowVal && Position <= 0)
BuyMarket();
else if (prevFast >= prevSlow && fastVal < slowVal && Position >= 0)
SellMarket();
prevFast = fastVal;
prevSlow = slowVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, emaFast);
DrawIndicator(area, emaSlow);
DrawOwnTrades(area);
}
}
}
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 global_stop_loss_time_strategy(Strategy):
def __init__(self):
super(global_stop_loss_time_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candles", "General")
self._ema_fast_length = self.Param("EmaFastLength", 8) \
.SetDisplay("EMA Fast", "Fast EMA period", "Indicators")
self._ema_slow_length = self.Param("EmaSlowLength", 21) \
.SetDisplay("EMA Slow", "Slow EMA period", "Indicators")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def EmaFastLength(self):
return self._ema_fast_length.Value
@property
def EmaSlowLength(self):
return self._ema_slow_length.Value
def OnReseted(self):
super(global_stop_loss_time_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(global_stop_loss_time_strategy, self).OnStarted2(time)
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
ema_fast = ExponentialMovingAverage()
ema_fast.Length = self.EmaFastLength
ema_slow = ExponentialMovingAverage()
ema_slow.Length = self.EmaSlowLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(ema_fast, ema_slow, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema_fast)
self.DrawIndicator(area, ema_slow)
self.DrawOwnTrades(area)
def _on_process(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fv = float(fast_value)
sv = float(slow_value)
if not self._has_prev:
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
return
if self._prev_fast <= self._prev_slow and fv > sv and self.Position <= 0:
self.BuyMarket()
elif self._prev_fast >= self._prev_slow and fv < sv and self.Position >= 0:
self.SellMarket()
self._prev_fast = fv
self._prev_slow = sv
def CreateClone(self):
return global_stop_loss_time_strategy()