Die Globale Stop-Timer-Strategie ist eine Risikomanagement-Überlagerung, die aus dem MetaTrader-Experten Exp_GStop_Tm konvertiert wurde.
Sie überwacht kontinuierlich den Portfoliowert bei jeder abgeschlossenen Kerze und hält den Handel an, sobald ein globales Gewinnziel
oder ein Verlustlimit erreicht wird. Zusätzlich kann sie den Handel auf ein benutzerdefiniertes Zeitfenster beschränken und alle offenen
Positionen zwangsweise schließen, wenn das Fenster geschlossen ist.
Funktionsweise
Wenn die Strategie startet, zeichnet sie den anfänglichen Portfolio-Saldo als Referenzpunkt auf.
Jedes Mal, wenn die abonnierte Kerzenserie schließt, liest die Strategie den aktuellen Portfoliowert und berechnet die
Differenz zum Anfangssaldo.
Je nach ausgewähltem StopCalculationMode wird die Differenz in einen Prozentsatz umgerechnet oder als Währung belassen.
Wenn der Verlust StopLoss übersteigt oder der Gewinn TakeProfit übersteigt, tritt die Strategie in den gestoppten Zustand ein, protokolliert das
Ereignis und sendet Marktorders, um verbleibende Positionen zu schließen.
Wenn das optionale Handelsfenster aktiviert ist und die aktuelle Zeit das Fenster verlässt, versucht die Strategie auch, die
Position zu glätten. Sobald die Positionsgröße null wird, wird das Stop-Flag zurückgesetzt, sodass der Handel innerhalb
des nächsten gültigen Fensters wieder aufgenommen werden kann.
Die Strategie öffnet selbst keine neuen Positionen. Sie ist darauf ausgelegt, andere Strategien oder manuelle Trades zu überwachen und die
Konto vor übermäßigem Drawdown zu schützen oder kontoweite Gewinne zu sichern.
Handelsfenster-Logik
Das Handelsfenster repliziert die ursprüngliche Expertenlogik:
Wenn die Startsstunde kleiner als die Endstunde ist, ist der Handel zwischen der Startminute (inklusiv) und der
Endminute (exklusiv) am selben Tag erlaubt.
Wenn Start- und Endstunde gleich sind, ist der Handel nur erlaubt, wenn die aktuelle Minute zwischen StartMinute
(inklusiv) und EndMinute (exklusiv) liegt.
Wenn die Startstunde größer als die Endstunde ist, erstreckt sich die Session über Mitternacht hinaus. Der Handel ist von der Startzeit
bis Mitternacht aktiviert und setzt von Mitternacht bis zur Endzeit am folgenden Tag fort.
Parameter
StopCalculationMode – wählen zwischen prozentbasierten oder währungsbasierten globalen Stops.
StopLoss – globaler Verlustschwellenwert. Wird als Prozentsatz behandelt, wenn der Prozentmodus aktiv ist, sonst als Kontowährung.
TakeProfit – globales Gewinnziel. Verwendet dieselbe Einheit wie StopLoss.
UseTradingWindow – Session-Filter aktivieren oder deaktivieren.
StartHour / StartMinute – Startzeit des erlaubten Handelsfensters.
EndHour / EndMinute – Endzeit des erlaubten Handelsfensters.
CandleType – Kerzenserie, die definiert, wie oft der Kontozustand ausgewertet wird.
Hinweise
Da Stop-Checks beim Kerzenschluss stattfinden, einen kleinen Zeitrahmen verwenden (z.B. eine Minute), wenn schnelle Reaktion
erforderlich ist.
Die Strategie schließt nur die von dieser Strategieinstanz verwaltete Position. Separate Instanzen ausführen, wenn mehrere
Wertpapiere individuelle Überwachung benötigen.
Zusammen mit anderen Handelsstrategien verwenden, indem es als übergeordnete Strategie angehängt oder auf demselben Instrument ausgeführt wird, um
kontoweiten Schutz zu bieten.
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 Timer strategy (simplified). Trades momentum with
/// time-based position management using EMA trend filter.
/// </summary>
public class GlobalStopTimerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _momentumLength;
private readonly StrategyParam<int> _emaLength;
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public int MomentumLength
{
get => _momentumLength.Value;
set => _momentumLength.Value = value;
}
public int EmaLength
{
get => _emaLength.Value;
set => _emaLength.Value = value;
}
public GlobalStopTimerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle Type", "Candles", "General");
_momentumLength = Param(nameof(MomentumLength), 10)
.SetGreaterThanZero()
.SetDisplay("Momentum Length", "Momentum period", "Indicators");
_emaLength = Param(nameof(EmaLength), 20)
.SetGreaterThanZero()
.SetDisplay("EMA Length", "EMA period", "Indicators");
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var momentum = new Momentum { Length = MomentumLength };
var ema = new ExponentialMovingAverage { Length = EmaLength };
decimal prevMomentum = 100m;
var hasPrev = false;
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(momentum, ema, (ICandleMessage candle, decimal momVal, decimal emaVal) =>
{
if (candle.State != CandleStates.Finished)
return;
if (!hasPrev)
{
prevMomentum = momVal;
hasPrev = true;
return;
}
if (!IsFormedAndOnlineAndAllowTrading())
{
prevMomentum = momVal;
return;
}
var close = candle.ClosePrice;
var bullishCross = prevMomentum <= 100m && momVal > 100m;
var bearishCross = prevMomentum >= 100m && momVal < 100m;
if (bullishCross && close > emaVal && Position <= 0)
BuyMarket();
else if (bearishCross && close < emaVal && Position >= 0)
SellMarket();
prevMomentum = momVal;
})
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, ema);
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 Momentum, ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class global_stop_timer_strategy(Strategy):
def __init__(self):
super(global_stop_timer_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle Type", "Candles", "General")
self._momentum_length = self.Param("MomentumLength", 10) \
.SetDisplay("Momentum Length", "Momentum period", "Indicators")
self._ema_length = self.Param("EmaLength", 20) \
.SetDisplay("EMA Length", "EMA period", "Indicators")
self._prev_momentum = 100.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@property
def MomentumLength(self):
return self._momentum_length.Value
@property
def EmaLength(self):
return self._ema_length.Value
def OnReseted(self):
super(global_stop_timer_strategy, self).OnReseted()
self._prev_momentum = 100.0
self._has_prev = False
def OnStarted2(self, time):
super(global_stop_timer_strategy, self).OnStarted2(time)
self._prev_momentum = 100.0
self._has_prev = False
momentum = Momentum()
momentum.Length = self.MomentumLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaLength
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(momentum, ema, self._on_process).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, subscription)
self.DrawIndicator(area, ema)
self.DrawOwnTrades(area)
def _on_process(self, candle, mom_value, ema_value):
if candle.State != CandleStates.Finished:
return
mv = float(mom_value)
if not self._has_prev:
self._prev_momentum = mv
self._has_prev = True
return
if not self.IsFormedAndOnlineAndAllowTrading():
self._prev_momentum = mv
return
close = float(candle.ClosePrice)
ev = float(ema_value)
bullish_cross = self._prev_momentum <= 100 and mv > 100
bearish_cross = self._prev_momentum >= 100 and mv < 100
if bullish_cross and close > ev and self.Position <= 0:
self.BuyMarket()
elif bearish_cross and close < ev and self.Position >= 0:
self.SellMarket()
self._prev_momentum = mv
def CreateClone(self):
return global_stop_timer_strategy()