Portierung des MetaTrader Expert Advisors "Macd diver rsi mt4" zum StockSharp High-Level API.
Handelt ein einzelnes Symbol mit RSI-Filtern kombiniert mit MACD-Divergenzerkennung für Zeitumkehrungen.
Es kann jeweils nur eine Marktposition offen sein; Die Strategie wartet auf den flachen Zustand, bevor sie ein neues Signal ausgibt.
Signallogik
Jede fertige Kerze aus dem ausgewählten Zeitrahmen speist vier an die Strategie gebundene Indikatoren:
Zwei unabhängige RelativeStrengthIndex-Instanzen (für überverkaufte und überkaufte Filter) haben einen Balken zurück abgetastet.
Zwei MovingAverageConvergenceDivergence-Indikatoren mit konfigurierbaren schnellen/langsamen EMA- und Signallängen.
Bulles Setup
Der vorherige Balken RSI muss unter dem konfigurierbaren Überverkaufsschwellenwert liegen.
Die aktuellsten MACD-Werte müssen einen lokalen Rückgang unterhalb eines dynamischen Schwellenwerts bilden (entspricht 3 Pips im aktuellen Instrument).
Historische Daten werden gescannt, um einen früheren MACD-Rückgang und das damit verbundene Preisschwankungstief zu lokalisieren. Divergenz wird bestätigt, wenn
Das MACD-Tief steigt, während der Preis ein niedrigeres Tief erreicht (regelmäßige Divergenz), oder das MACD-Tief fällt, während der Preis ein höheres Niveau erreicht
niedrig (versteckte Divergenz), passend zur ursprünglichen MQL-Logik.
Wenn die Strategie bestätigt ist und keine offene Position aufweist, wird ein Marktkauf mit richtungsspezifischen Volumen- und Risikoeinstellungen gesendet.
Bearisches Setup spiegelt die bullischen Regeln mit dem RSI-Überkauft-Filter und MACD-Spitzen wider. Divergenz wird validiert durch
Vergleich früherer Swing-Hochs mit dem aktuellen.
Unmittelbar nach einem Einstieg rechnet die Strategie die konfigurierten Stop-Loss- und Take-Profit-Abstände von Pips in Preiseinheiten um
(unter Berücksichtigung der ursprünglichen Punktformatregeln) und wendet sie über SetStopLoss / SetTakeProfit an.
Parameter
LowerRsiPeriod, LowerRsiThreshold – Zuordnung zu inp1_Lo_RSIperiod / inp1_Ro_Value.
BearishVolume, BearishStopLossPips, BearishTakeProfitPips – Zuordnung zu inp6_VolumeSize, inp6_StopLossPips, inp6_TakeProfitPips.
CandleType – Zeitrahmenquelle für alle Berechnungen.
Implementierungshinweise
Der Divergenzschwellenwert MACD wird von der aktuellen Punktgröße des Instruments abgeleitet und beträgt 3 Pips, was dem Standardwert von 0,0003 entspricht
Wird von der MQL-Version verwendet.
Kerze, MACD und Preisverlauf werden in begrenzten Listen (600 Elemente) gespeichert, um die Divergenz-Scanfenster ohne zu reproduzieren
Zuweisung großer Arrays.
Die Strategie verwendet SubscribeCandles(...).Bind(...), um alle Indikatoren in einem einzigen Durchgang zu aktualisieren und nur abgeschlossene Prozesse durchzuführen
Kerzen, genau wie die ursprüngliche Blockausführung einmal pro Balken.
Pip-Abstände werden vor dem Aufruf von SetStopLoss und SetTakeProfit in absolute Preisversätze umgewandelt und reproduziert
Punktformatregeln, die oben in der MQL-Quelle deklariert sind.
namespace StockSharp.Samples.Strategies;
using System;
using Ecng.Common;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.Messages;
/// <summary>
/// MACD Divergence RSI strategy: RSI filter + MACD signal line crossover.
/// Buys when RSI below threshold and MACD crosses above signal.
/// Sells when RSI above threshold and MACD crosses below signal.
/// </summary>
public class MacdDivergenceRsiStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _rsiPeriod;
private decimal _prevMacd;
private decimal _prevSignal;
private decimal _prevRsi;
private bool _hasPrev;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public int RsiPeriod { get => _rsiPeriod.Value; set => _rsiPeriod.Value = value; }
public MacdDivergenceRsiStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle timeframe", "General");
_rsiPeriod = Param(nameof(RsiPeriod), 14)
.SetGreaterThanZero()
.SetDisplay("RSI Period", "RSI period", "Indicators");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = 0;
_prevSignal = 0;
_prevRsi = 0;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_hasPrev = false;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd = { ShortMa = { Length = 12 }, LongMa = { Length = 26 } },
SignalMa = { Length = 9 }
};
var rsi = new RelativeStrengthIndex { Length = RsiPeriod };
var subscription = SubscribeCandles(CandleType);
subscription.BindEx(macd, rsi, ProcessCandle).Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue rsiValue)
{
if (candle.State != CandleStates.Finished) return;
if (!macdValue.IsFinal || !rsiValue.IsFinal) return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue typed) return;
if (typed.Macd is not decimal macdMain || typed.Signal is not decimal signal) return;
var rsi = rsiValue.ToDecimal();
if (_hasPrev)
{
if (_prevMacd <= _prevSignal && macdMain > signal && rsi < 40 && Position <= 0)
BuyMarket();
else if (_prevMacd >= _prevSignal && macdMain < signal && rsi > 60 && Position >= 0)
SellMarket();
}
_prevMacd = macdMain;
_prevSignal = signal;
_prevRsi = rsi;
_hasPrev = true;
}
}
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 MovingAverageConvergenceDivergenceSignal, RelativeStrengthIndex
from StockSharp.Algo.Strategies import Strategy
class macd_divergence_rsi_strategy(Strategy):
def __init__(self):
super(macd_divergence_rsi_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5)))
self._rsi_period = self.Param("RsiPeriod", 14)
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def RsiPeriod(self):
return self._rsi_period.Value
@RsiPeriod.setter
def RsiPeriod(self, value):
self._rsi_period.Value = value
def OnReseted(self):
super(macd_divergence_rsi_strategy, self).OnReseted()
self._prev_macd = 0.0
self._prev_signal = 0.0
self._prev_rsi = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(macd_divergence_rsi_strategy, self).OnStarted2(time)
self._has_prev = False
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = 12
macd.Macd.LongMa.Length = 26
macd.SignalMa.Length = 9
rsi = RelativeStrengthIndex()
rsi.Length = self.RsiPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, rsi, self._process_candle).Start()
def _process_candle(self, candle, macd_value, rsi_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not rsi_value.IsFinal:
return
if macd_value.Macd is None or macd_value.Signal is None:
return
macd_main = float(macd_value.Macd)
signal = float(macd_value.Signal)
rsi_val = float(rsi_value)
if self._has_prev:
if self._prev_macd <= self._prev_signal and macd_main > signal and rsi_val < 40 and self.Position <= 0:
self.BuyMarket()
elif self._prev_macd >= self._prev_signal and macd_main < signal and rsi_val > 60 and self.Position >= 0:
self.SellMarket()
self._prev_macd = macd_main
self._prev_signal = signal
self._prev_rsi = rsi_val
self._has_prev = True
def CreateClone(self):
return macd_divergence_rsi_strategy()