Die MACD Cleaner-Strategie ist eine Konvertierung des MetaTrader-5-Expert-Advisors „MACD Cleaner". Sie analysiert abgeschlossene Kerzen eines einzelnen Zeitrahmens und platziert Trades, wenn die MACD-Hauptlinie über drei aufeinanderfolgende geschlossene Bars monoton steigt oder fällt. Das System hält immer höchstens eine direktionale Position und dreht um, wenn das Momentum umkehrt.
Handelslogik
Bei jeder abgeschlossenen Kerze liest die Strategie die mit den konfigurierten Schnell-, Langsam- und Signalperioden berechnete MACD-Linie.
Wenn die letzten drei MACD-Werte nicht-abnehmend sind, bereitet die Strategie einen Long-Einstieg vor. Falls eine Short-Position vorhanden ist, wird diese zuerst geschlossen, dann eine neue Long-Position eröffnet.
Wenn die letzten drei MACD-Werte nicht-zunehmend sind, bereitet die Strategie einen Short-Einstieg vor. Vorhandene Long-Positionen werden geglättet, bevor der Short eröffnet wird.
Schützende Stop-Loss- und Take-Profit-Niveaus werden auf Kerzenhochs und -tiefs mit pip-basierten Offsets ausgewertet.
Wenn Trailing-Parameter aktiviert sind, wird der Stop in Handelsrichtung gezogen, sobald der Preis um mindestens den konfigurierten Trailing-Schritt voranschreitet.
Alle Ausstiegsorders werden als Marktorders unter Verwendung des aggregierten Positionsvolumens ausgegeben, um sicherzustellen, dass die gesamte Position geschlossen wird.
Parameter
Name
Standard
Beschreibung
CandleType
1-Stunden-Kerzen
Zeitrahmen für MACD-Berechnung und Orderauswertung.
TradeVolume
1
Basisvolumen für eine neue Position. Wenn die Gegenseite offen ist, wird das absolute Positionsvolumen zum Schließen hinzugefügt, bevor umgekehrt wird.
StopLossPips
35
Stop-Loss-Abstand in Pips vom Einstiegspreis. Auf null setzen zum Deaktivieren.
TakeProfitPips
30
Take-Profit-Abstand in Pips vom Einstiegspreis. Auf null setzen zum Deaktivieren.
TrailingStopPips
0
Trailing-Stop-Abstand. Bei null ist die Trailing-Logik deaktiviert.
TrailingStepPips
5
Mindest-Favoritenverschiebung (in Pips) bevor der Trailing-Stop angepasst wird. Ignoriert, wenn der Trailing-Stop deaktiviert ist.
MacdFastPeriod
15
Schnelle EMA-Länge für den MACD-Indikator.
MacdSlowPeriod
33
Langsame EMA-Länge für den MACD-Indikator.
MacdSignalPeriod
11
Signal-EMA-Länge für den MACD-Indikator.
Orderverwaltung
Long-Ausstiege: die Strategie gibt eine Marktverkaufsorder aus, wenn Stop-Loss, Take-Profit oder Trailing-Niveau getroffen wird.
Short-Ausstiege: eine Marktkauforder schließt die Position unter denselben Bedingungen, gespiegelt für Short-Trades.
Nachdem die Position vollständig geschlossen ist, wird der Trailing-Status zurückgesetzt, damit der nächste Trade mit frischen Niveaus beginnt.
Hinweise
Die Pip-Größe wird automatisch vom Instrument abgeleitet. Für Symbole mit 3 oder 5 Dezimalstellen entspricht der Pip zehn minimalen Preisschritten, entsprechend der ursprünglichen MetaTrader-Implementierung.
Die Logik wertet nur abgeschlossene Kerzen aus und reagiert nicht auf Intrabar-Änderungen.
Zum Deaktivieren des Risikomanagements die entsprechenden Pip-Abstände auf null setzen. Trailing erfordert sowohl TrailingStopPips als auch ein positives TrailingStepPips.
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 MacdCleanerStrategy : 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 MacdCleanerStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 12).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 macd_cleaner_strategy(Strategy):
def __init__(self):
super(macd_cleaner_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetGreaterThanZero().SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetGreaterThanZero().SetDisplay("Slow Period", "Slow EMA period", "Indicator")
self._stop_loss_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "Stop-loss in price steps", "Risk")
self._take_profit_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "Take-profit in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candles", "General")
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def candle_type(self):
return self._candle_type.Value
def OnReseted(self):
super(macd_cleaner_strategy, self).OnReseted()
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(macd_cleaner_strategy, self).OnStarted2(time)
self._fast_ind = ExponentialMovingAverage()
self._fast_ind.Length = self._fast_period.Value
self._slow_ind = ExponentialMovingAverage()
self._slow_ind.Length = self._slow_period.Value
subscription = self.SubscribeCandles(self.candle_type)
subscription.Bind(self._fast_ind, self._slow_ind, self._process_candle).Start()
def _process_candle(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if not self._fast_ind.IsFormed or not self._slow_ind.IsFormed:
self._prev_fast = fast
self._prev_slow = slow
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast
self._prev_slow = slow
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.Value > 0 and close <= self._entry_price - self._stop_loss_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close >= self._entry_price + self._take_profit_points.Value * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
elif self.Position < 0 and self._entry_price > 0:
if self._stop_loss_points.Value > 0 and close >= self._entry_price + self._stop_loss_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._take_profit_points.Value > 0 and close <= self._entry_price - self._take_profit_points.Value * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
return
if self._prev_fast <= self._prev_slow and fast > slow 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 < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast
self._prev_slow = slow
def CreateClone(self):
return macd_cleaner_strategy()