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
Abonnieren Sie die konfigurierte Kerzenserie und berechnen Sie den DeMarker-Indikator mit dem ausgewählten Zeitraum.
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.
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.
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.
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();
}
}