Auf GitHub ansehen

TCP-Pivot-Reversal-Limit-Strategie

Überblick

Die TCP-Pivot-Limit-Strategie ist eine Konvertierung des klassischen MetaTrader 4-Experten gpfTCPivotLimit.mq4. Der ursprüngliche Experte berechnet tägliche Pivot-Levels und sucht mithilfe stündlicher Kerzen nach falschen Ausbrüchen um diese Levels. Sobald ein Ausbruch fehlschlägt, geht die Strategie sofort einen Umkehrhandel ein, der auf die gegenüberliegenden Pivot-Levels abzielt. Diese Implementierung reproduziert dieselbe Logik unter Verwendung der übergeordneten Strategie StockSharp API.

Die Strategie basiert auf stündlichen Kerzen und hält zu jedem Zeitpunkt nur eine einzige offene Position. An jedem neuen Handelstag wird das Pivot-Raster anhand der Höchst-, Tiefst- und Schlusswerte des Vortages neu berechnet. Diese Ebenen leiten die Einstiegsauslöser, Stop-Loss, Take-Profit und optionales Trailing-Management.

Handelslogik

  1. Pivot-Berechnung

    • Bei der ersten Kerze jedes neuen Handelstages aggregiert die Strategie die Höchst-, Tiefst- und Schlusskurse des Vortages, um die klassischen Pivot-Level für Parketthändler zu berechnen (Pivot, R1–R3, S1–S3).
    • Jedes Mal, wenn neue Ebenen generiert werden, wird ein Protokolleintrag erstellt, damit Sie verfolgen können, wie sich das Raster entwickelt.
  2. Eintrittsbedingungen

    • Bei jeder abgeschlossenen stündlichen Kerze prüft die Strategie die letzten beiden abgeschlossenen Kerzen.
    • Eine Short-Position wird eröffnet, wenn die Kerze vor zwei Perioden über ein Widerstandsniveau gestiegen ist (oder bei/über diesem Niveau geschlossen hat), während sie darunter geöffnet hat, und die letzte Kerze wieder unter diesem Niveau geschlossen hat. Dies weist auf einen gescheiterten Ausbruch hin und lässt auf eine Umkehr nach unten schließen.
    • Eine Long-Position wird symmetrisch eröffnet, wenn der Markt unter ein Unterstützungsniveau fällt, die folgende Kerze jedoch wieder darüber schließt.
    • Es kann jeweils nur eine Position aktiv sein. Das Bestellvolumen wird durch den Parameter OrderVolume definiert.
  3. Exit-Management

    • Jeder Eintrag verwendet die Stop-Loss- und Take-Profit-Level, die durch die ausgewählte TargetMode-Voreinstellung definiert sind. Die Voreinstellungen spiegeln die TgtProfit-Optionen des ursprünglichen Expert Advisors wider und kombinieren verschiedene Pivot-Ebenen:
      Modus Kurzer Eintrag Kurzer Stopp Kurzes Ziel Langer Eintrag Langer Stopp Langes Ziel
      1 R1 R2 S1 S1 S2 R1
      2 R1 R2 S2 S1 S2 R2
      3 R2 R3 S1 S2 S3 R1
      4 R2 R3 S2 S2 S3 R2
      5 R2 R3 S3 S2 S3 R3
    • Wenn IntradayTrading aktiviert ist, wird jede offene Position beim Kerzenschluss um 23:00 Uhr geschlossen, um ein Halten über Nacht zu vermeiden.
    • Ein optionaler Trailing Stop in Punkten (Vielfache des Instrumentpreisschritts) emuliert das MetaTrader-Verhalten. Das Trailing wird erst aktiviert, nachdem die Bewegung um die konfigurierte Distanz fortgeschritten ist, und schließt den Handel, wenn der Preis um denselben Betrag zurückgeht.

Parameter

Parameter Beschreibung
OrderVolume Volumen, das sowohl für Kauf- als auch Verkaufsmarktaufträge verwendet wird.
TargetMode Ganzzahl von 1 bis 5, die auswählt, welche Widerstands-/Unterstützungskombination für Einstiege, Stopps und Ziele verwendet wird.
TrailingPoints Trailing-Stop-Distanz, gemessen in Preispunkten. Auf Null setzen, um das Nachziehen zu deaktivieren.
IntradayTrading Bei true werden die Positionen um 23:00 Uhr geschlossen, um den Intraday-Handel fortzusetzen.
CandleType Kerzendatentyp. Der Standardwert ist ein einstündiger Zeitrahmen, der dem ursprünglichen Experten entspricht.

Notizen

  • Die Strategie erwartet einen kontinuierlichen Strom stündlicher Kerzen. Die Anwendung auf andere Zeitrahmen ändert das Verhalten und sollte erneut getestet werden.
  • Stop-Loss- und Take-Profit-Niveaus werden anhand von Candle-Extremen bewertet, sodass Lücken zwischen den Niveaus zu Ausstiegen zu schlechteren Preisen führen können, genau wie in der MetaTrader-Version.
  • Das Trailing-Management wird bei Kerzenschlüssen und -tiefs/-hochs durchgeführt und entspricht weitgehend der ursprünglichen Tick-basierten Logik, bleibt aber in der StockSharp-Umgebung effizient.
using System;

using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;

namespace StockSharp.Samples.Strategies;

public class TcpPivotReversalLimitStrategy : Strategy
{
	private readonly StrategyParam<int> _rsiPeriod;
	private readonly StrategyParam<DataType> _candleType;

	private decimal _prevRsi;
	private bool _hasPrev;
	private int _cooldown;

	public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
	public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }

	public TcpPivotReversalLimitStrategy()
	{
		_rsiPeriod = Param(nameof(RsiPeriod), 14).SetDisplay("RSI Period", "RSI lookback", "Indicators");
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame()).SetDisplay("Candle Type", "Candle timeframe", "General");
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		base.OnReseted();
		_prevRsi = default;
		_hasPrev = default;
		_cooldown = default;
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);
		_hasPrev = false;
		var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
		var subscription = SubscribeCandles(CandleType);
		subscription.Bind(rsi, ProcessCandle).Start();
	}

	private void ProcessCandle(ICandleMessage candle, decimal rsi)
	{
		if (candle.State != CandleStates.Finished) return;
		if (!IsFormedAndOnlineAndAllowTrading()) return;

		if (!_hasPrev) { _prevRsi = rsi; _hasPrev = true; return; }
		if (_cooldown > 0)
		{
			_cooldown--;
			_prevRsi = rsi;
			return;
		}

		if (_prevRsi <= 30 && rsi > 30 && Position <= 0)
		{
			var volume = Volume + Math.Abs(Position);
			BuyMarket(volume);
			_cooldown = 2;
		}
		else if (_prevRsi >= 70 && rsi < 70 && Position >= 0)
		{
			var volume = Volume + Math.Abs(Position);
			SellMarket(volume);
			_cooldown = 2;
		}

		_prevRsi = rsi;
	}
}