MACD + Stochastic Trendfilterstrategie
Diese Strategie stellt das Verhalten des Expertenberaters MetaTrader aus dem Ordner MQL/7604 wieder her. Das ursprüngliche Skript basierte auf einem benutzerdefinierten Oszillator, der grüne und rote Puffer erzeugte. In der Praxis entsprechen die Zahlen (15, 3, 3) einem klassischen stochastischen Oszillator, daher verwendet der Port StockSharp den integrierten Indikator Stochastic zur Signalbestätigung, während MACD und ein Trendfilter EMA die Richtung verwalten.
Die Strategie handelt sowohl Long als auch Short. Es wartet auf einen stochastischen Crossover in Richtung des Handels, erfordert, dass das MACD-Histogramm seine Signallinie mit genügend Abstand von Null kreuzt, und verlangt, dass die EMA-Steigung mit dem Eintrag übereinstimmt. Das Risikomanagement spiegelt die MQL-Version wider: ein fester Stop-Loss, Take-Profit und ein punktbasierter Trailing-Stop, der das Schutzniveau verschärft, sobald der Handel in die Gewinnzone geht.
Indikatoren
- MovingAverageConvergenceDivergenceSignal mit den Parametern
fast = 12, slow = 26, signal = 9. Das MACD-Histogramm muss seine Signallinie kreuzen und dabei bei langen Setups unter Null und bei kurzen Setups über Null bleiben. Zusätzliche Schwellenwerte (MacdOpenLevel, MacdCloseLevel) erzwingen einen minimalen absoluten Abstand von der Nulllinie.
- Stochastic Oszillator mit
(Length = 15, KPeriod = 3, DPeriod = 3). Die %K-Linie spielt die Rolle des „grünen“ Puffers und muss für Long-Trades über %D liegen (darunter für Short-Trades). Derselbe Crossover wird zum Verlassen von Positionen verwendet.
- ExponentialMovingAverage mit Zeitraum
26. Der EMA bietet einen Richtungsfilter: Für einen Long-Trade muss der aktuelle EMA-Wert über dem EMA des vorherigen Balkens liegen, und umgekehrt für einen Short-Trade.
Eingabelogik
- Lange Einrichtung
- Stochastic %K > %D für die aktuell geschlossene Kerze.
- MACD Histogramm < 0 und > Signallinie auf dem aktuellen Balken.
- MACD Histogramm < Signallinie auf dem vorherigen Balken (d. h. jetzt bullischer Crossover).
|MACD| > MacdOpenLevel * price_step.
- EMA steigt (aktueller EMA > vorheriger EMA).
- Kurze Einrichtung
- Stochastic %K < %D für die aktuelle Kerze.
- MACD Histogramm > 0 und < Signallinie auf dem aktuellen Balken.
- MACD Histogramm > Signallinie auf dem vorherigen Balken (jetzt rückläufiger Crossover).
MACD > MacdOpenLevel * price_step.
- EMA fällt (aktueller EMA < vorheriger EMA).
Wenn das Konto bereits eine Position hält, werden keine neuen Aufträge generiert, bis der offene Handel geschlossen wird.
Exit-Logik
Während eine Position offen ist, erzwingt die Strategie kontinuierlich Folgendes:
- Indikatorausgang
- Long-Positionen werden geschlossen, wenn
%K < %D, MACD > 0, MACD < Signal, das vorherige MACD über seinem Signal lag und das absolute Histogramm MacdCloseLevel * price_step überschreitet.
- Short-Positionen werden geschlossen, wenn das Signal
%K > %D, MACD < 0, MACD >, das vorherige Signal MACD unter seinem Signal lag und |MACD| > MacdCloseLevel * price_step.
- Stop-Loss: konfiguriert durch
StopLossPoints, umgerechnet in Preiseinheiten über den PriceStep des Instruments.
- Take-Profit:
TakeProfitPoints multipliziert mit PriceStep.
- Trailing Stop: Sobald der Gewinn
TrailingStopPoints * PriceStep übersteigt, wird das Stop-Level erhöht (für Long-Positionen) oder gesenkt (für Short-Positionen), sodass der Trade immer mindestens diesen Gewinnbetrag sichert.
Parameter
| Name |
Beschreibung |
Standard |
TradeVolume |
Bestellgröße in Losen |
0.1 |
TakeProfitPoints |
Take-Profit-Distanz in Punkten |
10 |
StopLossPoints |
Stop-Loss-Distanz in Punkten |
50 |
TrailingStopPoints |
Trailing-Stop-Distanz in Punkten |
5 |
MacdOpenLevel |
Minimaler absoluter MACD-Wert für Einträge |
3 |
MacdCloseLevel |
Minimaler absoluter MACD-Wert für Exits |
2 |
MacdFastPeriod |
Schnelle Länge von EMA innerhalb von MACD |
12 |
MacdSlowPeriod |
Langsame Länge von EMA innerhalb von MACD |
26 |
MacdSignalPeriod |
MACD Signal EMA Länge |
9 |
EmaPeriod |
EMA Zeitraum für den Trendfilter |
26 |
StochasticLength |
Stochastic Lookback-Fenster |
15 |
StochasticKPeriod |
%K-Glättung |
3 |
StochasticDPeriod |
%D Glättung |
3 |
CandleType |
Für die Berechnungen verwendeter Zeitrahmen |
15m |
Notizen
- Alle Berechnungen verwenden nur fertige Kerzen und entsprechen der
start()-Schleife im ursprünglichen EA.
- Der vom Instrument gelieferte
PriceStep definiert einen Punkt. Wenn die Sicherheit einen Schritt nicht offenlegt, greift die Strategie auf 1 zurück.
- Der Code basiert ausschließlich auf dem übergeordneten API von StockSharp: Indikatoren werden durch
SubscribeCandles().BindEx(...) gebunden, es werden keine manuellen Verlaufspuffer erstellt und Aufträge verwenden BuyMarket/SellMarket wie in der MQL-Version.
using System;
using System.Collections.Generic;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// MACD strategy with stochastic confirmation and EMA trend filter.
/// Buy when MACD crosses above signal with stochastic K > D and price above EMA.
/// Sell when MACD crosses below signal with stochastic K < D and price below EMA.
/// </summary>
public class MacdStochasticFilterStrategy : Strategy
{
private readonly StrategyParam<int> _macdFastPeriod;
private readonly StrategyParam<int> _macdSlowPeriod;
private readonly StrategyParam<int> _macdSignalPeriod;
private readonly StrategyParam<int> _emaPeriod;
private readonly StrategyParam<int> _stochKLength;
private readonly StrategyParam<int> _stochDLength;
private readonly StrategyParam<DataType> _candleType;
private decimal? _prevMacd;
private decimal? _prevSignal;
/// <summary>
/// Fast EMA period inside MACD.
/// </summary>
public int MacdFastPeriod
{
get => _macdFastPeriod.Value;
set => _macdFastPeriod.Value = value;
}
/// <summary>
/// Slow EMA period inside MACD.
/// </summary>
public int MacdSlowPeriod
{
get => _macdSlowPeriod.Value;
set => _macdSlowPeriod.Value = value;
}
/// <summary>
/// Signal line period for MACD.
/// </summary>
public int MacdSignalPeriod
{
get => _macdSignalPeriod.Value;
set => _macdSignalPeriod.Value = value;
}
/// <summary>
/// Trend EMA period used as directional filter.
/// </summary>
public int EmaPeriod
{
get => _emaPeriod.Value;
set => _emaPeriod.Value = value;
}
/// <summary>
/// Stochastic %K length.
/// </summary>
public int StochKLength
{
get => _stochKLength.Value;
set => _stochKLength.Value = value;
}
/// <summary>
/// Stochastic %D length.
/// </summary>
public int StochDLength
{
get => _stochDLength.Value;
set => _stochDLength.Value = value;
}
/// <summary>
/// Type of candles used by the strategy.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public MacdStochasticFilterStrategy()
{
_macdFastPeriod = Param(nameof(MacdFastPeriod), 12)
.SetDisplay("MACD Fast", "Fast EMA period for MACD", "Indicators");
_macdSlowPeriod = Param(nameof(MacdSlowPeriod), 26)
.SetDisplay("MACD Slow", "Slow EMA period for MACD", "Indicators");
_macdSignalPeriod = Param(nameof(MacdSignalPeriod), 9)
.SetDisplay("MACD Signal", "Signal EMA period for MACD", "Indicators");
_emaPeriod = Param(nameof(EmaPeriod), 26)
.SetDisplay("Trend EMA", "EMA period for trend filter", "Indicators");
_stochKLength = Param(nameof(StochKLength), 14)
.SetDisplay("Stochastic K", "Look-back length for stochastic K", "Indicators");
_stochDLength = Param(nameof(StochDLength), 3)
.SetDisplay("Stochastic D", "Smoothing for D line", "Indicators");
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe for price data", "General");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacd = null;
_prevSignal = null;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_prevMacd = null;
_prevSignal = null;
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = MacdFastPeriod },
LongMa = { Length = MacdSlowPeriod }
},
SignalMa = { Length = MacdSignalPeriod }
};
var stochastic = new StochasticOscillator
{
K = { Length = StochKLength },
D = { Length = StochDLength }
};
var ema = new ExponentialMovingAverage { Length = EmaPeriod };
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, stochastic, ema, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue, IIndicatorValue stochValue, IIndicatorValue emaValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal || !stochValue.IsFinal || !emaValue.IsFinal)
return;
if (macdValue is not MovingAverageConvergenceDivergenceSignalValue macdData)
return;
if (macdData.Macd is not decimal macd || macdData.Signal is not decimal signal)
return;
if (stochValue is not StochasticOscillatorValue stochData)
return;
if (stochData.K is not decimal kVal || stochData.D is not decimal dVal)
return;
var emaVal = emaValue.ToDecimal();
if (_prevMacd is not decimal prevMacd || _prevSignal is not decimal prevSignal)
{
_prevMacd = macd;
_prevSignal = signal;
return;
}
// MACD crossover signals
var macdBullishCross = prevMacd <= prevSignal && macd > signal;
var macdBearishCross = prevMacd >= prevSignal && macd < signal;
// Long: MACD bullish cross + stochastic K > D + price above EMA
if (Position <= 0 && macdBullishCross && kVal > dVal && candle.ClosePrice > emaVal)
{
if (Position < 0)
BuyMarket();
BuyMarket();
}
// Short: MACD bearish cross + stochastic K < D + price below EMA
else if (Position >= 0 && macdBearishCross && kVal < dVal && candle.ClosePrice < emaVal)
{
if (Position > 0)
SellMarket();
SellMarket();
}
_prevMacd = macd;
_prevSignal = signal;
}
}
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 (
ExponentialMovingAverage,
MovingAverageConvergenceDivergenceSignal,
StochasticOscillator
)
from StockSharp.Algo.Strategies import Strategy
class macd_stochastic_filter_strategy(Strategy):
"""MACD strategy with stochastic confirmation and EMA trend filter.
Buy when MACD crosses above signal with stochastic K > D and price above EMA.
Sell when MACD crosses below signal with stochastic K < D and price below EMA."""
def __init__(self):
super(macd_stochastic_filter_strategy, self).__init__()
self._macd_fast_period = self.Param("MacdFastPeriod", 12) \
.SetDisplay("MACD Fast", "Fast EMA period for MACD", "Indicators")
self._macd_slow_period = self.Param("MacdSlowPeriod", 26) \
.SetDisplay("MACD Slow", "Slow EMA period for MACD", "Indicators")
self._macd_signal_period = self.Param("MacdSignalPeriod", 9) \
.SetDisplay("MACD Signal", "Signal EMA period for MACD", "Indicators")
self._ema_period = self.Param("EmaPeriod", 26) \
.SetDisplay("Trend EMA", "EMA period for trend filter", "Indicators")
self._stoch_k_length = self.Param("StochKLength", 14) \
.SetDisplay("Stochastic K", "Look-back length for stochastic K", "Indicators")
self._stoch_d_length = self.Param("StochDLength", 3) \
.SetDisplay("Stochastic D", "Smoothing for D line", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe for price data", "General")
self._prev_macd = None
self._prev_signal = None
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def MacdFastPeriod(self):
return self._macd_fast_period.Value
@property
def MacdSlowPeriod(self):
return self._macd_slow_period.Value
@property
def MacdSignalPeriod(self):
return self._macd_signal_period.Value
@property
def EmaPeriod(self):
return self._ema_period.Value
@property
def StochKLength(self):
return self._stoch_k_length.Value
@property
def StochDLength(self):
return self._stoch_d_length.Value
def OnReseted(self):
super(macd_stochastic_filter_strategy, self).OnReseted()
self._prev_macd = None
self._prev_signal = None
def OnStarted2(self, time):
super(macd_stochastic_filter_strategy, self).OnStarted2(time)
self._prev_macd = None
self._prev_signal = None
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.MacdFastPeriod
macd.Macd.LongMa.Length = self.MacdSlowPeriod
macd.SignalMa.Length = self.MacdSignalPeriod
stochastic = StochasticOscillator()
stochastic.K.Length = self.StochKLength
stochastic.D.Length = self.StochDLength
ema = ExponentialMovingAverage()
ema.Length = self.EmaPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, stochastic, ema, self._process_candle).Start()
def _process_candle(self, candle, macd_value, stoch_value, ema_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal or not stoch_value.IsFinal or not ema_value.IsFinal:
return
macd_raw = macd_value.Macd if hasattr(macd_value, 'Macd') else None
signal_raw = macd_value.Signal if hasattr(macd_value, 'Signal') else None
if macd_raw is None or signal_raw is None:
return
macd_main = float(macd_raw)
signal_line = float(signal_raw)
k_raw = stoch_value.K if hasattr(stoch_value, 'K') else None
d_raw = stoch_value.D if hasattr(stoch_value, 'D') else None
if k_raw is None or d_raw is None:
return
k_val = float(k_raw)
d_val = float(d_raw)
ema_val = float(ema_value)
if self._prev_macd is None or self._prev_signal is None:
self._prev_macd = macd_main
self._prev_signal = signal_line
return
prev_macd = self._prev_macd
prev_signal = self._prev_signal
# MACD crossover signals
macd_bullish_cross = prev_macd <= prev_signal and macd_main > signal_line
macd_bearish_cross = prev_macd >= prev_signal and macd_main < signal_line
close = float(candle.ClosePrice)
# Long: MACD bullish cross + stochastic K > D + price above EMA
if self.Position <= 0 and macd_bullish_cross and k_val > d_val and close > ema_val:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
# Short: MACD bearish cross + stochastic K < D + price below EMA
elif self.Position >= 0 and macd_bearish_cross and k_val < d_val and close < ema_val:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._prev_macd = macd_main
self._prev_signal = signal_line
def CreateClone(self):
return macd_stochastic_filter_strategy()