Timer-System

Überblick

Strategien in StockSharp unterstützen ein integriertes Timer-System, mit dem Aktionen in festgelegten Zeitintervallen ausgeführt werden können. Timer basieren auf dem Mechanismus WhenIntervalElapsed des Connectors und funktionieren sowohl im Live-Handel als auch beim Backtesting korrekt, wobei im Backtesting die virtuelle Zeit des Emulators verwendet wird.

Timer sind nützlich für:

  • Regelmäßige Prüfungen der Marktbedingungen
  • Portfolio-Rebalancing in festen Intervallen
  • Schließen von Positionen nach Zeit
  • Überwachung des Strategiezustands

ITimerHandler-Schnittstelle

Der Timer wird über die Schnittstelle ITimerHandler verwaltet, die die folgenden Member bereitstellt:

Member Beschreibung
Start() Startet den Timer. Gibt ITimerHandler für Method Chaining zurück
Stop() Stoppt den Timer. Gibt ITimerHandler für Method Chaining zurück
Interval Auslöseintervall des Timers (lesbar und schreibbar)
IsStarted Gibt an, ob der Timer läuft
Dispose() Gibt Ressourcen frei und stoppt den Timer

Methoden zur Timer-Erstellung

CreateTimer

Erstellt einen Timer, startet ihn aber nicht. Der Start erfolgt über einen separaten Aufruf von Start():

ITimerHandler CreateTimer(TimeSpan interval, Action callback);

StartTimer

Erstellt und startet einen Timer sofort. Entspricht CreateTimer(...).Start():

ITimerHandler StartTimer(TimeSpan interval, Action callback);

Das Intervall muss ein positiver Wert sein (> TimeSpan.Zero), andernfalls wird eine Ausnahme ausgelöst.

Timer-Verwaltung

Ein Timer kann gestoppt und neu gestartet werden:

var timer = CreateTimer(TimeSpan.FromMinutes(1), MyCallback);

// Starten
timer.Start();

// Stoppen
timer.Stop();

// Intervall ändern
timer.Interval = TimeSpan.FromMinutes(5);

// Erneut starten
timer.Start();

// Ressourcen freigeben
timer.Dispose();

Verwendungsbeispiel

public class TimerStrategy : Strategy
{
    private ITimerHandler _checkTimer;
    private ITimerHandler _closeTimer;

    private readonly StrategyParam<TimeSpan> _checkInterval;
    private readonly StrategyParam<TimeSpan> _maxHoldTime;

    public TimeSpan CheckInterval
    {
        get => _checkInterval.Value;
        set => _checkInterval.Value = value;
    }

    public TimeSpan MaxHoldTime
    {
        get => _maxHoldTime.Value;
        set => _maxHoldTime.Value = value;
    }

    public TimerStrategy()
    {
        _checkInterval = Param(nameof(CheckInterval), TimeSpan.FromMinutes(1));
        _maxHoldTime = Param(nameof(MaxHoldTime), TimeSpan.FromHours(4));
    }

    protected override void OnStarted2(DateTime time)
    {
        base.OnStarted2(time);

        // Timer für regelmäßige Prüfungen der Marktbedingungen
        _checkTimer = StartTimer(CheckInterval, OnCheckTimer);

        // Timer für erzwungenes Schließen von Positionen (erstellt, aber nicht gestartet)
        _closeTimer = CreateTimer(MaxHoldTime, OnCloseTimer);

        var subscription = SubscribeCandles(TimeSpan.FromMinutes(5));

        subscription
            .Bind(ProcessCandle)
            .Start();
    }

    private void OnCheckTimer()
    {
        if (!IsFormedAndOnlineAndAllowTrading())
            return;

        this.AddInfoLog("Checking market conditions at {0}", CurrentTime);

        // Regelmäßige Prüfung des Positionszustands
        if (Position != 0)
        {
            this.AddInfoLog("Current position: {0}", Position);
        }
    }

    private void OnCloseTimer()
    {
        if (Position != 0)
        {
            this.AddInfoLog("Position hold time expired, closing");
            ClosePosition();

            // Close-Timer nach Auslösung stoppen
            _closeTimer.Stop();
        }
    }

    private void ProcessCandle(ICandleMessage candle)
    {
        if (!IsFormedAndOnlineAndAllowTrading())
            return;

        if (candle.OpenPrice < candle.ClosePrice && Position == 0)
        {
            BuyMarket();

            // Timer für erzwungenes Schließen starten
            _closeTimer.Start();
        }
    }
}

In diesem Beispiel werden zwei Timer verwendet: einer für die regelmäßige Zustandsprüfung (StartTimer -- erstellt und sofort gestartet) und ein weiterer zur Begrenzung der Positionshaltedauer (CreateTimer -- erstellt, aber erst beim Einstieg in eine Position gestartet).