Auf GitHub ansehen

DeMarker Pending 2 Strategie

Überblick

Die Strategie repliziert die Kernlogik des MetaTrader-Experten „DeMarker Pending 2“ unter Verwendung des StockSharp-High-Level-API. Es wertet einen DeMarker-Oszillator im Arbeitszeitraum aus und bereitet ausstehende Kauf- oder Verkaufseinträge vor, wenn der Indikator konfigurierbare Schwellenwerte überschreitet. Aufträge können als Stop- oder Limit-Anforderungen mit einem zusätzlichen Abstand zum aktuellen Marktpreis erstellt werden. Ein Sitzungsfilter, Spread Guard und Distanzkontrollen halten neue Einträge unter Kontrolle.

Handelslogik

  1. Abonnieren Sie die konfigurierte Kerzenserie und berechnen Sie den DeMarker-Indikator mit dem ausgewählten Zeitraum.
  2. Wenn der vorherige Wert über dem unteren Niveau liegt und der aktuelle Wert darunter fällt, wird eine lange ausstehende Bestellung in die Warteschlange gestellt. Wenn der vorherige Wert unter dem oberen Niveau liegt und der aktuelle Wert darüber liegt, wird eine kurze Pending-Order in die Warteschlange gestellt. Es wird nur ein Signal pro Kerze verarbeitet.
  3. Ausstehende Orders werden als Stop- oder Limit-Orders unter Verwendung der in Punkten ausgedrückten Einrückungsdistanz platziert. Bestehende Bestellungen können vor der neuen Anfrage storniert werden, wenn die Ersatzoption aktiviert ist. Die Strategie begrenzt die Gesamtzahl der offenen Positionen plus ausstehender Aufträge und erzwingt einen Mindestabstand zum aktuellen durchschnittlichen Positionspreis.
  4. Long- und Short-Positionen nutzen optionale Stop-Loss-, Take-Profit- und Trailing-Logik. Schutzniveaus werden in Preispunkten berechnet und bei jeder geschlossenen Kerze überwacht. Trailing-Stops passen sich an, sobald die Position den Aktivierungsgewinn und die zusätzliche Trailing-Step-Distanz erzielt.
  5. Ein Spread-Filter verhindert neue Orders, wenn die beste Geld-/Briefspanne den konfigurierten Schwellenwert überschreitet. Optionale Sitzungsgrenzen können neue Einträge außerhalb des zulässigen Handelsfensters deaktivieren.

Parameter

Name Beschreibung
Funktionierende Kerzen Zeitrahmen für Signale und Schutzkontrollen.
Bestellvolumen Standardvolumen für ausstehende Orders.
Stop-Loss (Punkte) Anfängliche Stop-Loss-Distanz in Preispunkten.
Take-Profit (Punkte) Anfängliche Take-Profit-Distanz in Preispunkten.
Trailing-Aktivierung (Punkte) Erforderlicher Gewinn, bevor der Trailing Stop greift.
Trailing Stop (Punkte) Abstand zwischen Preis und Trailing Stop.
Trailing Step (Punkte) Zusätzliche Verstärkung erforderlich, um den Trailing Stop zu bewegen.
Trail On Close Aktualisieren Sie den Trailing Stop nur bei fertigen Kerzen, wenn er aktiviert ist.
Maximale Positionen Maximale Anzahl offener Positionen plus ausstehende Aufträge. Null deaktiviert die Obergrenze.
Mindestentfernung (Punkte) Mindestabstand vom aktuellen Positionspreis zu neuen ausstehenden Einträgen.
Verwenden Sie Stop-Orders Platzieren Sie Stop-Orders, wenn dies zutrifft, andernfalls werden Limit-Orders verwendet.
Single ausstehend Lassen Sie jeweils nur eine aktive ausstehende Bestellung zu.
Ausstehende ersetzen Stornieren Sie ausstehende ausstehende Orders, bevor Sie eine neue aufgeben.
Ausstehender Offset (Punkte) Einzug für neue ausstehende Preise im Verhältnis zum Markt.
Max Spread (Punkte) Maximal zulässiger Spread, bevor die Auftragserteilung übersprungen wird.
Verwenden Sie den Sitzungsfilter Aktivieren oder deaktivieren Sie den Handelsfensterfilter.
Startstunde/Minute, Endstunde/Minute Sitzungsgrenzen, wenn der Sitzungsfilter aktiv ist.
DeMarker-Zeitraum Mittelungszeitraum für den DeMarker-Oszillator.
Obere Ebene Schwelle, die kurze Setups auslöst.
Untere Ebene Schwelle, die lange Setups auslöst.

Notizen

  • Auftragsablauf und Money-Management-Risikodimensionierung des ursprünglichen Experten werden nicht portiert. Stattdessen wird ein fester Volumenparameter verwendet.
  • Stop-Loss- und Take-Profit-Level werden bei geschlossenen Kerzen anhand von Hoch-/Tiefpreisen bewertet, die von der Intrabar-Ausführung in MetaTrader abweichen können.
  • Die Trailing-Logik wird nur bei geschlossenen Kerzen ausgewertet. Echtzeit-Tick-basiertes Trailing wird nicht reproduziert.
  • Ausstehende Aufträge basieren auf den besten Geld-/Briefkursen, die von der Datenquelle bereitgestellt werden. Stellen Sie sicher, dass Abonnements der Stufe 1 verfügbar sind.
namespace StockSharp.Samples.Strategies;

using System;

using Ecng.Common;

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

/// <summary>
/// Pending order strategy driven by the DeMarker oscillator.
/// Simplified from "DeMarker Pending 2" to use market orders on threshold crossovers.
/// </summary>
public class DeMarkerPending2Strategy : Strategy
{
	private readonly StrategyParam<DataType> _candleType;
	private readonly StrategyParam<int> _demarkerPeriod;
	private readonly StrategyParam<decimal> _demarkerUpperLevel;
	private readonly StrategyParam<decimal> _demarkerLowerLevel;

	private RelativeStrengthIndex _rsi;
	private decimal? _prevOscillator;

	/// <summary>
	/// Candle type for calculations.
	/// </summary>
	public DataType CandleType
	{
		get => _candleType.Value;
		set => _candleType.Value = value;
	}

	/// <summary>
	/// DeMarker oscillator period.
	/// </summary>
	public int DemarkerPeriod
	{
		get => _demarkerPeriod.Value;
		set => _demarkerPeriod.Value = value;
	}

	/// <summary>
	/// Upper DeMarker threshold for sell signal.
	/// </summary>
	public decimal DemarkerUpperLevel
	{
		get => _demarkerUpperLevel.Value;
		set => _demarkerUpperLevel.Value = value;
	}

	/// <summary>
	/// Lower DeMarker threshold for buy signal.
	/// </summary>
	public decimal DemarkerLowerLevel
	{
		get => _demarkerLowerLevel.Value;
		set => _demarkerLowerLevel.Value = value;
	}

	public DeMarkerPending2Strategy()
	{
		_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(60).TimeFrame())
			.SetDisplay("Candle Type", "Timeframe for calculations", "General");

		_demarkerPeriod = Param(nameof(DemarkerPeriod), 14)
			.SetDisplay("DeMarker Period", "DeMarker oscillator period", "Indicator")
			.SetGreaterThanZero();

		_demarkerUpperLevel = Param(nameof(DemarkerUpperLevel), 0.7m)
			.SetDisplay("Upper Level", "Overbought threshold", "Indicator");

		_demarkerLowerLevel = Param(nameof(DemarkerLowerLevel), 0.3m)
			.SetDisplay("Lower Level", "Oversold threshold", "Indicator");
	}

	/// <inheritdoc />
	protected override void OnStarted2(DateTime time)
	{
		base.OnStarted2(time);

		_prevOscillator = null;
		_rsi = new RelativeStrengthIndex { Length = DemarkerPeriod };

		var subscription = SubscribeCandles(CandleType);
		subscription
			.Bind(_rsi, ProcessCandle)
			.Start();

		var area = CreateChartArea();
		if (area != null)
		{
			DrawCandles(area, subscription);
			DrawOwnTrades(area);
		}
	}

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

		if (!_rsi.IsFormed)
		{
			_prevOscillator = rsiValue / 100m;
			return;
		}

		if (_prevOscillator is not decimal prev)
		{
			_prevOscillator = rsiValue / 100m;
			return;
		}

		var oscillatorValue = rsiValue / 100m;
		var volume = Volume;
		if (volume <= 0)
			volume = 1;

		// Cross above lower level from below => buy
		if (prev < DemarkerLowerLevel && oscillatorValue >= DemarkerLowerLevel)
		{
			if (Position <= 0)
				BuyMarket(Position < 0 ? Math.Abs(Position) + volume : volume);
		}
		// Cross below upper level from above => sell
		else if (prev > DemarkerUpperLevel && oscillatorValue <= DemarkerUpperLevel)
		{
			if (Position >= 0)
				SellMarket(Position > 0 ? Math.Abs(Position) + volume : volume);
		}

		_prevOscillator = oscillatorValue;
	}

	/// <inheritdoc />
	protected override void OnReseted()
	{
		_rsi = null;
		_prevOscillator = null;

		base.OnReseted();
	}
}