Cronex DeMarker Crossover-Strategie
Überblick
Die Cronex DeMarker Crossover-Strategie reproduziert den MetaTrader-Indikator Cronex DeMarker und wandelt ihn in ein automatisiertes Handelssystem um. Der ursprüngliche Indikator stellt den DeMarker-Oszillator zusammen mit zwei linear gewichteten gleitenden Durchschnitten (LWMAs) dar. Die Strategie spiegelt dieses Setup wider, bewertet bullische und bärische Übergänge zwischen den geglätteten Oszillatorlinien und wandelt sie in Marktaufträge um. Dadurch kann die Handelslogik sofort reagieren, wenn sich die Dynamik je nach Indikator vom Abwärts- zum Aufwärtsdruck (und umgekehrt) ändert.
Indikatorkonstruktion
- DeMarker-Oszillator – Misst die Beziehung zwischen der aktuellen Kerze und der vorherigen Kerze:
- Wenn das aktuelle Hoch höher ist als das vorherige Hoch, entspricht der positive Druck der Differenz der Höchststände; andernfalls ist es Null.
- Wenn das aktuelle Tief niedriger ist als das vorherige Tief, entspricht der Unterdruck dem Abstand zwischen den Tiefs; andernfalls ist es Null.
- Die Summen von Über- und Unterdruck über
DeMarkerPeriod bar bilden den Oszillatorwert deMax / (deMax + deMin).
- Schneller LWMA – Ein linear gewichteter gleitender Durchschnitt mit der Periode
FastMaPeriod wird auf die DeMarker-Rohwerte angewendet, um die neuesten Oszillatoränderungen hervorzuheben.
- Langsamer LWMA – Ein weiterer linear gewichteter gleitender Durchschnitt mit der Periode
SlowMaPeriod glättet denselben DeMarker-Stream, um eine langsamere Bestätigungslinie zu bilden.
Die Strategie führt jede fertige Kerze diesem Indikatorstapel zu und stimmt dabei genau mit den Pufferberechnungen aus der ursprünglichen MQ4-Datei überein.
Handelslogik
- Warten Sie, bis der DeMarker-Oszillator und beide LWMAs vollständig geformt sind.
- Berechnen Sie nach jeder abgeschlossenen Kerze den neuen DeMarker-Wert und aktualisieren Sie beide gleitenden Durchschnitte.
- Erkennen Sie Übergänge zwischen der schnellen und langsamen LWMA-Serie:
- Bullish Crossover – Der schnelle LWMA bewegt sich von unten nach oben über den langsamen LWMA. Die Strategie schließt jegliches Short-Engagement und eröffnet eine Long-Marktposition.
- Bearish Crossover – Der schnelle LWMA bewegt sich von oberhalb nach unterhalb des langsamen LWMA. Die Strategie schließt alle Long-Positionen und eröffnet eine Short-Marktposition.
- Aufträge werden übersprungen, solange die Strategie noch nicht festgelegt ist, während sie offline ist oder der Handel deaktiviert ist.
Bei entgegengesetzten Signalen werden die Positionen sofort umgekehrt. Das bestehende Exposure wird geschlossen, indem die erforderliche Menge zur neuen Marktorder hinzugefügt wird.
Parameter
| Parameter |
Beschreibung |
Standard |
DeMarkerPeriod |
Anzahl der Kerzen, die zum Aufbau des DeMarker-Oszillators verwendet werden. |
25 |
FastMaPeriod |
Periode des schnellen linear gewichteten gleitenden Durchschnitts, der auf neue Oszillatorwerte reagiert. |
14 |
SlowMaPeriod |
Zeitraum des langsamen linearen gewichteten gleitenden Durchschnitts, der die Richtung bestätigt. |
25 |
CandleType |
Von der Strategie verarbeitete Kerzenserie (Zeitrahmen oder anderer DataType). |
1 Hour Zeitrahmen |
Details zur Implementierung
- Verwendet die übergeordnete
SubscribeCandles API. Indikatoren werden nur aktualisiert, wenn eine Kerze den Status Finished erreicht, um ein Neuzeichnen in der Mitte des Balkens zu vermeiden.
- Die Strategie basiert auf den integrierten Indikatoren
DeMarker und WeightedMovingAverage von StockSharp, um die MQ4-Puffer originalgetreu nachzubilden.
- Es wird automatisch ein Diagrammbereich erstellt, in dem die Preiskerzen zusammen mit dem Oszillator und beiden gleitenden Durchschnitten zur visuellen Bestätigung dargestellt werden.
StartProtection() wird beim Start aufgerufen, sodass der Positionsschutz genau einmal aktiviert wird, wie in den Projektrichtlinien gefordert.
Nutzung
- Hängen Sie die Strategie an das gewünschte Wertpapier an und weisen Sie den bevorzugten Kerzentyp zu (z. B. Kerzen mit 1-Stunden-Zeitrahmen).
- Konfigurieren Sie den DeMarker und die gleitenden Durchschnittsperioden so, dass sie mit dem ursprünglichen Indikator übereinstimmen, oder optimieren Sie sie zur Optimierung.
- Führen Sie die Strategie aus. Der Handel beginnt, sobald die Indikatoren vollständig gebildet sind und der Handel zulässig ist.
- Beobachten Sie das gezeichnete Diagramm, um zu sehen, wie die DeMarker-Oszillator- und LWMA-Crossover-Signale die Einträge antreiben.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that replicates the Cronex DeMarker indicator setup and trades crossovers of its smoothed values.
/// </summary>
public class CronexDeMarkerCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _deMarkerPeriod;
private readonly StrategyParam<int> _fastMaPeriod;
private readonly StrategyParam<int> _slowMaPeriod;
private readonly StrategyParam<DataType> _candleType;
private DeMarker _deMarker;
private WeightedMovingAverage _fastMa;
private WeightedMovingAverage _slowMa;
private decimal? _previousFast;
private decimal? _previousSlow;
/// <summary>
/// DeMarker indicator period.
/// </summary>
public int DeMarkerPeriod
{
get => _deMarkerPeriod.Value;
set => _deMarkerPeriod.Value = value;
}
/// <summary>
/// Fast linear weighted moving average period.
/// </summary>
public int FastMaPeriod
{
get => _fastMaPeriod.Value;
set => _fastMaPeriod.Value = value;
}
/// <summary>
/// Slow linear weighted moving average period.
/// </summary>
public int SlowMaPeriod
{
get => _slowMaPeriod.Value;
set => _slowMaPeriod.Value = value;
}
/// <summary>
/// Candle type processed by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Initializes a new instance of the <see cref="CronexDeMarkerCrossoverStrategy"/>.
/// </summary>
public CronexDeMarkerCrossoverStrategy()
{
_deMarkerPeriod = Param(nameof(DeMarkerPeriod), 25)
.SetRange(2, 150)
.SetDisplay("DeMarker Period", "Length of the DeMarker oscillator", "Indicators")
;
_fastMaPeriod = Param(nameof(FastMaPeriod), 14)
.SetRange(2, 100)
.SetDisplay("Fast LWMA Period", "Length of the fast linear weighted moving average", "Indicators")
;
_slowMaPeriod = Param(nameof(SlowMaPeriod), 25)
.SetRange(2, 150)
.SetDisplay("Slow LWMA Period", "Length of the slow linear weighted moving average", "Indicators")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Time frame of processed candles", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_deMarker = null;
_fastMa = null;
_slowMa = null;
_previousFast = null;
_previousSlow = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
// Instantiate indicators matching the original MetaTrader logic.
_deMarker = new DeMarker
{
Length = DeMarkerPeriod
};
_fastMa = new WeightedMovingAverage
{
Length = FastMaPeriod
};
_slowMa = new WeightedMovingAverage
{
Length = SlowMaPeriod
};
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawIndicator(area, _deMarker);
DrawIndicator(area, _fastMa);
DrawIndicator(area, _slowMa);
DrawOwnTrades(area);
}
StartProtection(null, null);
}
private void ProcessCandle(ICandleMessage candle)
{
// Only act on completed candles to avoid repainting effects.
if (candle.State != CandleStates.Finished)
return;
if (_deMarker is null || _fastMa is null || _slowMa is null)
return;
// Update the DeMarker oscillator with the full candle data.
var deMarkerResult = _deMarker.Process(new CandleIndicatorValue(_deMarker, candle));
if (deMarkerResult.IsEmpty)
{
return;
}
var deMarkerValue = deMarkerResult.GetValue<decimal>();
// Smooth the oscillator with linear weighted moving averages.
var fastResult = _fastMa.Process(new DecimalIndicatorValue(_fastMa, deMarkerValue, candle.OpenTime) { IsFinal = true });
if (fastResult.IsEmpty) return;
var fastValue = fastResult.GetValue<decimal>();
var slowResult = _slowMa.Process(new DecimalIndicatorValue(_slowMa, deMarkerValue, candle.OpenTime) { IsFinal = true });
if (slowResult.IsEmpty) return;
var slowValue = slowResult.GetValue<decimal>();
// Ensure all indicators accumulated enough samples.
if (!_deMarker.IsFormed || !_fastMa.IsFormed || !_slowMa.IsFormed)
{
_previousFast = fastValue;
_previousSlow = slowValue;
return;
}
var previousFast = _previousFast;
var previousSlow = _previousSlow;
_previousFast = fastValue;
_previousSlow = slowValue;
if (!previousFast.HasValue || !previousSlow.HasValue)
return;
// Check readiness and trading permissions before sending orders.
// indicators formed check removed
var crossUp = previousFast.Value <= previousSlow.Value && fastValue > slowValue;
var crossDown = previousFast.Value >= previousSlow.Value && fastValue < slowValue;
if (crossUp)
{
// Close short exposure and establish a long position.
if (Position < 0)
BuyMarket();
BuyMarket();
}
else if (crossDown)
{
// Close long exposure and establish a short position.
if (Position > 0)
SellMarket();
SellMarket();
}
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import DeMarker, WeightedMovingAverage, CandleIndicatorValue
from StockSharp.Algo.Strategies import Strategy
from indicator_extensions import *
class cronex_de_marker_crossover_strategy(Strategy):
"""Cronex DeMarker crossover strategy. Smooths the DeMarker oscillator with
fast and slow WMA and trades on their crossover."""
def __init__(self):
super(cronex_de_marker_crossover_strategy, self).__init__()
self._de_marker_period = self.Param("DeMarkerPeriod", 25) \
.SetDisplay("DeMarker Period", "Length of the DeMarker oscillator", "Indicators")
self._fast_ma_period = self.Param("FastMaPeriod", 14) \
.SetDisplay("Fast LWMA Period", "Length of the fast linear weighted moving average", "Indicators")
self._slow_ma_period = self.Param("SlowMaPeriod", 25) \
.SetDisplay("Slow LWMA Period", "Length of the slow linear weighted moving average", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Time frame of processed candles", "General")
self._de_marker = None
self._fast_ma = None
self._slow_ma = None
self._previous_fast = None
self._previous_slow = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def DeMarkerPeriod(self):
return self._de_marker_period.Value
@property
def FastMaPeriod(self):
return self._fast_ma_period.Value
@property
def SlowMaPeriod(self):
return self._slow_ma_period.Value
def OnReseted(self):
super(cronex_de_marker_crossover_strategy, self).OnReseted()
self._de_marker = None
self._fast_ma = None
self._slow_ma = None
self._previous_fast = None
self._previous_slow = None
def OnStarted2(self, time):
super(cronex_de_marker_crossover_strategy, self).OnStarted2(time)
self._de_marker = DeMarker()
self._de_marker.Length = self.DeMarkerPeriod
self._fast_ma = WeightedMovingAverage()
self._fast_ma.Length = self.FastMaPeriod
self._slow_ma = WeightedMovingAverage()
self._slow_ma.Length = self.SlowMaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(self._process_candle).Start()
def _process_candle(self, candle):
if candle.State != CandleStates.Finished:
return
if self._de_marker is None or self._fast_ma is None or self._slow_ma is None:
return
dm_input = CandleIndicatorValue(self._de_marker, candle)
dm_input.IsFinal = True
dm_result = self._de_marker.Process(dm_input)
if dm_result.IsEmpty:
return
dm_value = float(dm_result)
fast_result = process_float(self._fast_ma, dm_value, candle.OpenTime, True)
if fast_result.IsEmpty:
return
fast_value = float(fast_result)
slow_result = process_float(self._slow_ma, dm_value, candle.OpenTime, True)
if slow_result.IsEmpty:
return
slow_value = float(slow_result)
if not self._de_marker.IsFormed or not self._fast_ma.IsFormed or not self._slow_ma.IsFormed:
self._previous_fast = fast_value
self._previous_slow = slow_value
return
previous_fast = self._previous_fast
previous_slow = self._previous_slow
self._previous_fast = fast_value
self._previous_slow = slow_value
if previous_fast is None or previous_slow is None:
return
cross_up = previous_fast <= previous_slow and fast_value > slow_value
cross_down = previous_fast >= previous_slow and fast_value < slow_value
if cross_up:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
elif cross_down:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
def CreateClone(self):
return cronex_de_marker_crossover_strategy()