Die Cryptocurrency-Divergence-Strategie sucht nach klassischen Momentum-Divergenzen zwischen Kursverlauf und Relative Strength Index (RSI) und bestätigt die Trendrichtung mit gleitenden Durchschnitten und MACD. Der ursprüngliche MetaTrader-Expert-Advisor setzte auf Multi-Zeitrahmen-Momentum-Prüfungen, Geldmanagement und umfangreiche Trailing-Logik. Dieser StockSharp-Port bewahrt den Kern des Systems durch:
Erkennen bullischer Divergenzen, wenn der Preis ein tieferes Tief bildet, der RSI aber ein höheres Tief.
Erkennen bärischer Divergenzen, wenn der Preis ein höheres Hoch bildet, der RSI aber ein tieferes Hoch.
Validierung von Setups mit schneller/langsamer gleitender Durchschnittslinie und MACD-Linie gegenüber Signallinie.
Positionsverwaltung über konfigurierbaren Stop Loss, Take Profit, Break-even und Trailing Stop in Preisschritten.
Die Strategie ist für Spot-Kryptowährungen ausgelegt, kann aber auf jedes Instrument angewendet werden, das genügend Volatilität und klare Swing-Punkte liefert.
Indikatoren
Einfacher gleitender Durchschnitt (SMA): Eine schnelle und eine langsame SMA bilden den primären Trendfilter.
Relative Strength Index (RSI): Liefert die Momentum-Pivotwerte zur Messung der Divergenzstärke.
Moving Average Convergence Divergence (MACD): Bestätigt, dass das Momentum zur erkannten Divergenzrichtung passt.
Alle Indikatoren sind über die High-Level-API gebunden, sodass kein manuelles Puffern erforderlich ist.
Handelslogik
Den konfigurierten Kerzentyp abonnieren und SMA-, RSI- und MACD-Werte auf jeder abgeschlossenen Bar berechnen.
Die jüngsten Swing-Hochs und -Tiefs zusammen mit ihren RSI-Werten verfolgen. Nur monotone Erweiterungen (neue höhere Hochs oder tiefere Tiefs) aktualisieren die Swing-Daten.
Eine bullische Divergenz erscheint, wenn ein frisches tieferes Tief im Preis mit einem höheren RSI-Tief gekoppelt ist. Der Trade erfordert außerdem, dass die schnelle SMA über der langsamen SMA liegt, die MACD-Linie die Signallinie übersteigt und der RSI unter dem neutralen Niveau (Standard 45) bleibt, um überverkaufte Bedingungen sicherzustellen.
Eine bärische Divergenz erfordert ein neues höheres Hoch im Preis mit einem niedrigeren RSI-Hoch, schnelle SMA unter langsamer SMA, MACD-Linie unter ihrem Signal und RSI über dem neutralen bärischen Niveau (Standard 55).
Die Strategie öffnet nur eine Nettoposition gleichzeitig. Umkehrungen schließen die bestehende Position und eröffnen sofort in Gegenrichtung, wenn die Signale übereinstimmen.
Risikomanagement
Volumen: Benutzerdefinierte Tradegröße für alle Marktorders.
Stop Loss / Take Profit: In Preisschritten angegeben und nach jeder Ausführung mit dem tatsächlichen Ausführungspreis angefügt.
Break-even-Verschiebung: Ersetzt den Stop Loss optional durch einen Offset über/unter dem Einstieg, sobald der Preis eine konfigurierbare Distanz zurückgelegt hat.
Trailing Stop: Zieht optional hinter dem Schlusskurs in fester Schrittweite nach. Nach Aktivierung hat der Trailing Stop Vorrang vor dem ursprünglichen Stop Loss.
Stops und Ziele werden auf jeder abgeschlossenen Kerze ausgewertet, wodurch ein deterministisches Verhalten entsteht, das Backtests und Echtzeitausführung angleicht.
Parameter
Name
Beschreibung
CandleType
Kerzenserie für die Analyse (standardmäßig 15-Minuten-Zeitrahmen).
TradeVolume
Ordervolumen für alle Einstiege.
FastMaLength / SlowMaLength
Perioden der schnellen und langsamen SMAs.
RsiLength
RSI-Berechnungslänge.
RsiBullishLevel / RsiBearishLevel
RSI-Schwellen, die überverkaufte und überkaufte Zonen zur Divergenzbestätigung definieren.
Jeder Parameter wird über StrategyParam<T> bereitgestellt, sodass er im StockSharp Designer optimiert werden kann.
Nutzungshinweise
Binden Sie die Strategie an ein Kryptowährungssymbol und stellen Sie sicher, dass das Instrument PriceStep und Board definiert hat. Ohne Preisschritt kann die Strategie keine Stops berechnen.
Stimmen Sie den Kerzentyp auf den gehandelten Markt ab (z. B. 15m, 1h). Divergenzerkennung ist zeitrahmensensitiv.
Passen Sie Stop- und Zielabstände an die Volatilität des Instruments an. Kryptopaare mit fünf Dezimalstellen benötigen oft größere Schrittzahlen.
Aktivieren Sie Break-even oder Trailing erst, nachdem historische Tests genügend Gewinnpuffer gezeigt haben; aggressives Trailing kann Trades zu früh beenden.
Überwachen Sie die Strategie im StockSharp Designer oder Marktdatenfenster, um Indikatorausrichtung und ausgeführte Trades zu visualisieren.
Unterschiede zur MQL-Version
Geldbasiertes Trailing und Equity-Stop-Schutz wurden in eine preisschrittbasierte Stop-Verwaltung vereinfacht.
Multi-Zeitrahmen-Momentum-Prüfungen wurden aus Klarheitsgründen durch MACD-Bestätigung auf einem Zeitrahmen ersetzt.
E-Mail-/Benachrichtigungs-Nebeneffekte werden ausgelassen, weil sie in StockSharp-Ökosystemen extern behandelt werden.
Trotz dieser Anpassungen bleiben die zentrale Divergenzerkennung und Schutzlogik der Absicht des ursprünglichen Expert-Advisors treu.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
public class CryptocurrencyDivergenceStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _stopLossPoints;
private readonly StrategyParam<int> _takeProfitPoints;
private ExponentialMovingAverage _fast;
private ExponentialMovingAverage _slow;
private decimal _prevFast;
private decimal _prevSlow;
private decimal _entryPrice;
private int _cooldown;
public int FastPeriod { get => _fastPeriod.Value; set => _fastPeriod.Value = value; }
public int SlowPeriod { get => _slowPeriod.Value; set => _slowPeriod.Value = value; }
public int StopLossPoints { get => _stopLossPoints.Value; set => _stopLossPoints.Value = value; }
public int TakeProfitPoints { get => _takeProfitPoints.Value; set => _takeProfitPoints.Value = value; }
public CryptocurrencyDivergenceStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator");
_slowPeriod = Param(nameof(SlowPeriod), 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator");
_stopLossPoints = Param(nameof(StopLossPoints), 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk");
_takeProfitPoints = Param(nameof(TakeProfitPoints), 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk");
}
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
yield return (Security, TimeSpan.FromMinutes(5).TimeFrame());
}
protected override void OnReseted()
{
base.OnReseted();
_fast = null; _slow = null;
_prevFast = 0; _prevSlow = 0; _entryPrice = 0; _cooldown = 0;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_fast = new ExponentialMovingAverage { Length = FastPeriod };
_slow = new ExponentialMovingAverage { Length = SlowPeriod };
var subscription = SubscribeCandles(TimeSpan.FromMinutes(5).TimeFrame());
subscription.Bind(_fast, _slow, ProcessCandle);
subscription.Start();
}
private void ProcessCandle(ICandleMessage candle, decimal fastValue, decimal slowValue)
{
if (candle.State != CandleStates.Finished) return;
if (!_fast.IsFormed || !_slow.IsFormed) { _prevFast = fastValue; _prevSlow = slowValue; return; }
if (_cooldown > 0) { _cooldown--; _prevFast = fastValue; _prevSlow = slowValue; return; }
var close = candle.ClosePrice;
var step = Security?.PriceStep ?? 1m;
if (Position > 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close <= _entryPrice - StopLossPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close >= _entryPrice + TakeProfitPoints * step) { SellMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
else if (Position < 0 && _entryPrice > 0)
{
if (StopLossPoints > 0 && close >= _entryPrice + StopLossPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
if (TakeProfitPoints > 0 && close <= _entryPrice - TakeProfitPoints * step) { BuyMarket(); _entryPrice = 0; _cooldown = 100; _prevFast = fastValue; _prevSlow = slowValue; return; }
}
if (_prevFast <= _prevSlow && fastValue > slowValue && Position <= 0)
{ if (Position < 0) BuyMarket(); BuyMarket(); _entryPrice = close; _cooldown = 100; }
else if (_prevFast >= _prevSlow && fastValue < slowValue && Position >= 0)
{ if (Position > 0) SellMarket(); SellMarket(); _entryPrice = close; _cooldown = 100; }
_prevFast = fastValue; _prevSlow = slowValue;
}
}
import clr
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan
from StockSharp.Messages import DataType, CandleStates
from StockSharp.Algo.Indicators import ExponentialMovingAverage
from StockSharp.Algo.Strategies import Strategy
class cryptocurrency_divergence_strategy(Strategy):
def __init__(self):
super(cryptocurrency_divergence_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200) \
.SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400) \
.SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(cryptocurrency_divergence_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(cryptocurrency_divergence_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = float(self.Security.PriceStep) if self.Security is not None and self.Security.PriceStep is not None else 1.0
if self.Position > 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._prev_fast <= self._prev_slow and fast_val > slow_val and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._entry_price = close
self._cooldown = 100
elif self._prev_fast >= self._prev_slow and fast_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return cryptocurrency_divergence_strategy()