Die MACD Power-Strategie ist ein Multi-Timeframe-Momentum-System, das aus dem ursprünglichen MetaTrader-Expert-Advisor konvertiert wurde. Die Logik kombiniert ein Paar linear gewichteter gleitender Durchschnitte (LWMA), berechnet auf dem primären Zeitrahmen, zwei MACD-Varianten, einen Momentum-Filter auf einem höheren Zeitrahmen und einen monatlichen MACD-Bias. Die Strategie versucht, an impulsiven Bewegungen teilzunehmen, sobald Momentum und Trendbedingungen des höheren Zeitrahmens übereinstimmen.
Kernlogik
Primäre gleitende Durchschnitte – Ein schneller und ein langsamer LWMA des typischen Kerzenpreises (((High + Low + Close) / 3)). Die Strategie erfordert, dass der schnelle Durchschnitt unter dem langsamen liegt, bevor ein Signal berücksichtigt wird, was den Originalcode widerspiegelt, der auf Rücksetzer innerhalb eines dominanten bearischen Gefälles wartet, bevor in Richtung des monatlichen Bias eingegangen wird.
Doppelte MACD-Bestätigung – Zwei MACD-Indikatoren mit Parametern (12, 26, 1) und (6, 13, 1) müssen beide über null für Long-Trades oder unter null für Short-Trades liegen. Diese Werte reproduzieren die MacdMAIN1- und MacdMAIN2-Bedingungen des MQL-Experten, die kurzfristige Beschleunigung messen.
Momentum-Filter – Momentum (Länge 14) wird auf einem höheren Zeitrahmen berechnet, der aus der primären Kerzengröße abgeleitet wird (z.B. 15-Minuten-Basis → 1-Stunden-Momentum). Der absolute Abstand von 100 wird über die letzten drei Momentum-Lesungen überwacht; mindestens eine davon muss den konfigurierten Schwellenwert überschreiten, um zu bestätigen, dass sich der Preis entschlossen bewegt.
Monatlicher MACD-Bias – Ein monatlicher (12, 26, 9) MACD (identisch mit MacdMAIN0/MacdSIGNAL0 im EA) muss seine Hauptlinie über der Signallinie für Long-Trades und unter der Signallinie für Shorts haben. Dies schützt vor dem Handel gegen den dominanten Makrotrend.
Handelsverwaltung
Entry-Sizing – Der Parameter OrderVolume definiert die Basis-Ordergröße. Wenn eine Positionsumkehr erforderlich ist, fügt die Engine automatisch die Größe der entgegengesetzten Position hinzu, sodass das Nettovolumen in einer einzigen Market-Order umgekehrt wird.
Take-Profit / Stop-Loss – Absolute Distanzen werden in Instrumentenpunkten ausgedrückt und mit Security.PriceStep in Preise umgerechnet (mit sicherem Fallback auf 1).
Trailing-Stop – Sobald sich der Preis um TrailingActivationPoints zugunsten bewegt, verfolgt der Stop den höchsten (Long) oder niedrigsten (Short) Preis mit einem durch TrailingOffsetPoints definierten Offset.
Break-Even – Wenn der Preis BreakEvenTriggerPoints erreicht, wird ein synthetischer Break-Even-Stop bei Entry ± BreakEvenOffsetPoints gesetzt. Wenn der Preis auf dieses Niveau zurückgeht, wird die Position geschlossen.
Handelslimit – MaxTrades begrenzt die Anzahl der Positionseröffnungen pro Lauf; sobald der Schwellenwert erreicht ist, werden keine neuen Einstiege ausgegeben.
Parameter
Name
Beschreibung
Standard
CandleType
Primärer Zeitrahmen für die Signalgenerierung.
15-Minuten-Kerzen
FastMaLength
Länge des schnellen LWMA (typischer Preis).
6
SlowMaLength
Länge des langsamen LWMA (typischer Preis).
85
MomentumLength
Momentum-Lookback auf dem höheren Zeitrahmen.
14
MomentumBuyThreshold
Minimaler absoluter Abstand von 100 für bullisches Momentum.
0.3
MomentumSellThreshold
Minimaler absoluter Abstand von 100 für bearisches Momentum.
0.3
TakeProfitPoints
Take-Profit-Distanz in Instrumentenpunkten.
50
StopLossPoints
Stop-Loss-Distanz in Instrumentenpunkten.
20
TrailingActivationPoints
Gewinn (Punkte) erforderlich, bevor Trailing aktiviert.
40
TrailingOffsetPoints
Abstand (Punkte) zwischen Trailing-Stop und Extrempreis.
40
BreakEvenTriggerPoints
Gewinn (Punkte), der den Break-Even-Schutz aktiviert.
30
BreakEvenOffsetPoints
Offset (Punkte) beim Verschieben des Stops auf Break-Even.
30
MaxTrades
Maximale Anzahl der Trades pro Sitzung.
10
OrderVolume
Basis-Ordervolumen.
1
Unterschiede zum MQL-Experten
Die Strategie verwendet die StockSharp High-Level-API (SubscribeCandles + Bind/BindEx) anstelle von direktem Tick-Polling. Indikatorwerte werden nur nach abgeschlossenen Kerzen verarbeitet.
Geldbasierte Trailing- und Eigenkapital-Stop-Blöcke aus dem Originalcode werden nicht portiert, da das kontoebene Geldmanagement normalerweise durch das StockSharp-Risikoframework gehandhabt wird. Stattdessen bleiben punktbasiertes Trailing und Break-Even erhalten und können konfiguriert werden, um das EA-Verhalten zu emulieren.
Alerts, Benachrichtigungen und manuelle Ordermodifikationshilfen aus MQL werden weggelassen; die StockSharp-Engine verwaltet Orders direkt über Market-Calls.
Verwendungshinweise
Wählen Sie den primären Zeitrahmen durch Einstellen von CandleType. Höherer Zeitrahmen-Momentum und monatlicher MACD werden automatisch gemäß dem in GetMomentumCandleType() implementierten Mapping abgeleitet.
Richten Sie TakeProfitPoints, StopLossPoints und die Trailing/Break-Even-Parameter an der Tick-Größe des Instruments aus. Die Standardwerte spiegeln die 5-stelligen Forex-Einstellungen des EA wider, können aber für andere Märkte angepasst werden.
Überwachen Sie den MaxTrades-Zähler bei automatisierten Backtests; setzen Sie ihn auf eine große Zahl, wenn das martingaleartige Stapelverhalten des ursprünglichen EA gewünscht wird.
Für die visuelle Analyse aktivieren Sie die Diagrammdarstellung in der GUI – die Implementierung zeichnet standardmäßig Kerzen und die beiden LWMA-Kurven.
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 MacdPowerStrategy : 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 MacdPowerStrategy()
{
_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_power_strategy(Strategy):
"""
MACD Power: EMA crossover with manual SL/TP via price steps.
"""
def __init__(self):
super(macd_power_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_power_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_power_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_power_strategy()