Die Macd-Secrets-Strategie ist ein Multi-Timeframe-Momentum-Folgesystem, inspiriert vom ursprünglichen "Macd Secrets I" Expert Advisor für MetaTrader. Die StockSharp-Portierung nutzt die High-Level-API und konzentriert sich darauf, die MACD-Richtung über drei Zeitrahmen auszurichten, während Trades mit einer linear gewichteten gleitenden Durchschnittsbasis (LWMA) und einer Momentum-Abweichungsprüfung gefiltert werden. Die Strategie hält zu jedem Zeitpunkt nur eine einzelne Nettoposition und bietet damit ein vereinfachtes, transparentes Risikoprofil im Vergleich zum Quell-EA, der mehrere Orders pyramidisieren konnte.
Signalerzeugung
Long-Setup
Die schnelle LWMA liegt auf dem Ausführungszeitrahmen unter der langsamen LWMA, was signalisiert, dass der Preis nahe der unteren Seite des Trendkanals handelt (der ursprüngliche EA verwendet denselben Filter).
Die MACD-Linie liegt auf allen verfolgten Zeitrahmen über ihrer Signallinie: Ausführung, Trendbestätigung und monatliche Bestätigung. Dies spiegelt die dreifache MACD-Ausrichtung der MQL-Version.
Mindestens eine der letzten drei Momentum-Messungen auf dem Trendzeitrahmen weicht um das konfigurierte Minimum (Standard 0.3) von 100 ab. Die Abweichungsberechnung reproduziert die MathAbs(100 - Momentum)-Logik des EA.
Es ist keine Position offen.
Wenn die Bedingungen erfüllt sind, wird eine Markt-Kauforder mit dem konfigurierten Volumen platziert.
Short-Setup
Die MACD-Linie liegt auf Ausführungs-, Trend- und Monatszeitrahmen unter ihrer Signallinie.
Mindestens eine der letzten drei Momentum-Abweichungen auf dem Trendzeitrahmen überschreitet den konfigurierten Short-Schwellenwert.
Es ist keine Position offen (die Portierung vermeidet Hedging und Skalierung).
Wenn alle Regeln gelten, wird eine Markt-Verkaufsorder gesendet.
Trade-Management
Die Strategie kann optional Schutzorders mit punktbasierten Distanzen für Stop-Loss und Take-Profit starten. Diese Distanzen werden mit dem Wertpapier-Preisschritt multipliziert, um Punkte in Preisinkremente umzuwandeln.
Trailing-Stop-, Breakeven- oder equitybasierte Schutzlogik aus dem ursprünglichen EA ist nicht enthalten; StockSharp-Schutz wird einmal beim Start angewendet.
Signale werden nur auf abgeschlossenen Kerzen bewertet, um Intrabar-Rauschen zu vermeiden.
Multi-Timeframe-Daten
Primärer Zeitrahmen: Ausführungsfrequenz (Standard 15 Minuten). MACD und das LWMA-Paar werden hier berechnet.
Trend-Zeitrahmen: Bestätigung auf höherem Zeitrahmen (Standard 1 Stunde). Sowohl MACD als auch Momentum laufen auf dieser Subscription. Momentum-Abweichungen werden aus den letzten drei geschlossenen Kerzen gesammelt.
Monats-Zeitrahmen: langfristige MACD-Bestätigung (Standard 30 Tage zur Annäherung an einen Kalendermonat).
Die Strategie überschreibt GetWorkingSecurities, sodass alle drei Subscriptions vom Connector von Anfang an angefordert werden.
Parameter
Name
Beschreibung
Standard
OrderVolume
Handelsvolumen in Lots. Muss positiv sein.
0.1
TakeProfitPoints
Take-Profit-Distanz in Punkten. Auf null setzen, um zu deaktivieren.
50
StopLossPoints
Stop-Loss-Distanz in Punkten. Auf null setzen, um zu deaktivieren.
20
FastMaPeriod
Länge der schnellen LWMA auf dem primären Zeitrahmen.
6
SlowMaPeriod
Länge der langsamen LWMA auf dem primären Zeitrahmen.
85
MacdFastPeriod
Schnelle EMA-Periode, die von jeder MACD-Instanz verwendet wird.
12
MacdSlowPeriod
Langsame EMA-Periode, die von jeder MACD-Instanz verwendet wird.
26
MacdSignalPeriod
Signal-EMA-Periode für MACD.
9
MomentumPeriod
Momentum-Rückblick auf dem Trendzeitrahmen.
14
MomentumBuyThreshold
Minimale absolute Abweichung von 100 für Long-Trades.
0.3
MomentumSellThreshold
Minimale absolute Abweichung von 100 für Short-Trades.
0.3
PrimaryCandleType
Kerzentyp für die Ausführung. Standard ist ein 15-Minuten-Zeitrahmen.
15m
TrendCandleType
Kerzentyp für Bestätigung. Standard ist ein 1-Stunden-Zeitrahmen.
1h
MonthlyCandleType
Kerzentyp für langfristige Bestätigung. Standard ist eine 30-Tage-Bar.
30d
Nutzungshinweise
Der LWMA-Filter ist bewusst asymmetrisch: Nur Long-Trades verlangen, dass die schnelle LWMA unter der langsamen LWMA liegt, passend zum im MQL-Skript beobachteten Verhalten.
Da die Portierung eine einzelne Nettoposition handelt, überspringt sie die martingaleartige Positionsgrößenlogik aus dem Quellcode (LotsOptimized). Wenn Stacking erforderlich ist, kann es wieder eingeführt werden, indem gefülltes Volumen verfolgt und mit OrderVolume verglichen wird.
Stellen Sie sicher, dass der verbundene Broker oder die Datenquelle alle drei Kerzenzeitrahmen bereitstellen kann; andernfalls bleibt die Strategie inaktiv und wartet auf Indikatorbildung.
Erwägen Sie, den Monatszeitrahmen für Märkte anzupassen, in denen 30-Tage-Kerzen nicht verfügbar sind, indem Sie einen benutzerdefinierten DataType-Parameter bereitstellen.
Die Strategie arbeitet vollständig auf geschlossenen Kerzen und liest historische Indikatorbuffer nicht direkt, wodurch sie die StockSharp-Richtlinien zur Indikatornutzung einhält.
Unterschiede zum ursprünglichen EA
Trailing-Stop, Breakeven, geldbasierte Ausstiege und kontoweiter Equity-Schutz werden nicht portiert. Stattdessen wird StockSharp-Schutz mit statischen Distanzen verwendet.
Order-Pyramiding und Martingale-Logik werden aus Gründen der Klarheit weggelassen. Die Positionsgröße bleibt konstant.
Benachrichtigungen (Alerts, E-Mails, Push-Nachrichten) sind nicht implementiert.
Haftungsausschluss
Algorithmischer Handel birgt erhebliche finanzielle Risiken. Testen Sie die Strategie mit historischen Daten und in einer simulierten Umgebung, bevor Sie sie mit echtem Kapital einsetzen.
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 MacdSecretsStrategy : 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 MacdSecretsStrategy()
{
_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_secrets_strategy(Strategy):
"""
MACD Secrets: EMA crossover with manual SL/TP via price steps.
"""
def __init__(self):
super(macd_secrets_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 12).SetDisplay("Fast Period", "Fast EMA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50).SetDisplay("Slow Period", "Slow EMA 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._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_secrets_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_secrets_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_secrets_strategy()