Dieses Beispiel wandelt den ursprünglichen MetaTrader 4-Expertenberater MACD_v1.mq4 in eine StockSharp-Strategie auf hoher Ebene um. Der Algorithmus verfolgt Überkreuzungen der gleitenden durchschnittlichen Konvergenzdivergenz (MACD) und handelt in Richtung des neuen Trends. Optionale Schutzausstiege reproduzieren das Verhalten des ursprünglichen Beraters: einen Stop-Loss, einen entfernten Take-Profit und ein Teilgewinnziel, das die Hälfte der aktuellen Position liquidiert.
Handelslogik
Datenquelle – Die Strategie abonniert die konfigurierte Kerzenserie (standardmäßig 5-Minuten-Kerzen) und bindet einen MovingAverageConvergenceDivergenceSignal-Indikator.
Eintrittsbedingungen:
Geben Sie long ein, wenn die MACD-Linie die Signallinie kreuzt. Wenn eine Short-Position aktiv ist, wird diese geschlossen, bevor die Long-Position eröffnet wird.
Geben Sie short ein, wenn die MACD-Linie die Signallinie unterschreitet. Wenn eine Long-Position besteht, wird diese zuerst geschlossen.
Exit-Bedingungen:
Gegenüberliegende MACD-Kreuzung schließt die aktuelle Position und öffnet eine neue Position in der entgegengesetzten Richtung.
Ein konfigurierbarer Take-Profit und Stop-Loss, der von StartProtection verwaltet wird, spiegelt die ursprünglichen TP/SL-Parameter wider (gemessen in Instrumentenpunkten).
Ein Teilgewinnziel schließt die Hälfte der offenen Position, sobald der Preis um einen bestimmten Betrag vom Einstiegsniveau steigt. Der Teilausstieg wird nur einmal pro Position ausgelöst.
Parameter
Name
Standard
Beschreibung
Schnelle Periode
23
Schnelle EMA-Länge für die MACD-Berechnung (spiegelt den MQL-Parameter a = 2300 wider).
Langsamer Zeitraum
40
Langsame EMA-Länge für die MACD-Berechnung (b = 4000 in der Quelle).
Signalperiode
8
Länge der Signalleitung (c = 800 in der Quelle).
Gewinn mitnehmen
500
Abstand in Preispunkten für die schützende Take-Profit-Order. Zum Deaktivieren auf 0 setzen.
Stop-Loss
80
Abstand in Preispunkten für die schützende Stop-Loss-Order. Zum Deaktivieren auf 0 setzen.
Teilgewinn
70
Abstand in Preispunkten, um die Hälfte der offenen Position zu schließen. Auf 0 setzen, um Teilausstiege zu deaktivieren.
Kerzentyp
Zeitrahmen von 5 Minuten
Für Indikatorberechnungen verwendete Kerzenserien.
Notizen
Indikatorparameter wurden auf typische MACD-Längen (23/40/8) skaliert, da das MQL-Skript sie als Hundertstel (2300/4000/800) ausdrückte.
Die Strategie stellt das Teilausstiegsflag automatisch wieder her, wenn eine neue Position akkumuliert wird.
Hilfsmittel zum Zeichnen von Diagrammen heben Kerzen, MACD-Werte und die Trades der Strategie hervor, wenn ein Diagrammfeld verfügbar ist.
Die Volumenverarbeitung basiert auf der Eigenschaft der Basisstrategie Volume. Passen Sie es vor Beginn der Strategie an Ihre Instrumentengröße an.
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 MacdSignalCrossoverStrategy : Strategy
{
private readonly StrategyParam<int> _fastPeriod;
private readonly StrategyParam<int> _slowPeriod;
private readonly StrategyParam<int> _signalPeriod;
private readonly StrategyParam<DataType> _candleType;
private bool _prevMacdAboveSignal;
private bool _hasPrev;
public int FastPeriod
{
get => _fastPeriod.Value;
set => _fastPeriod.Value = value;
}
public int SlowPeriod
{
get => _slowPeriod.Value;
set => _slowPeriod.Value = value;
}
public int SignalPeriod
{
get => _signalPeriod.Value;
set => _signalPeriod.Value = value;
}
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public MacdSignalCrossoverStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 23);
_slowPeriod = Param(nameof(SlowPeriod), 40);
_signalPeriod = Param(nameof(SignalPeriod), 8);
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame());
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_prevMacdAboveSignal = false;
_hasPrev = false;
}
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var macd = new MovingAverageConvergenceDivergenceSignal
{
Macd =
{
ShortMa = { Length = FastPeriod },
LongMa = { Length = SlowPeriod },
},
SignalMa = { Length = SignalPeriod }
};
var subscription = SubscribeCandles(CandleType);
subscription
.BindEx(macd, ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle, IIndicatorValue macdValue)
{
if (candle.State != CandleStates.Finished)
return;
if (!macdValue.IsFinal)
return;
var macdTyped = macdValue as MovingAverageConvergenceDivergenceSignalValue;
if (macdTyped == null)
return;
var macdLine = macdTyped.Macd;
var signalLine = macdTyped.Signal;
if (macdLine == null || signalLine == null)
return;
var isMacdAboveSignal = macdLine.Value > signalLine.Value;
if (!_hasPrev)
{
_hasPrev = true;
_prevMacdAboveSignal = isMacdAboveSignal;
return;
}
var crossedAbove = isMacdAboveSignal && !_prevMacdAboveSignal;
var crossedBelow = !isMacdAboveSignal && _prevMacdAboveSignal;
if (crossedAbove)
{
if (Position < 0)
BuyMarket();
if (Position <= 0)
BuyMarket();
}
else if (crossedBelow)
{
if (Position > 0)
SellMarket();
if (Position >= 0)
SellMarket();
}
_prevMacdAboveSignal = isMacdAboveSignal;
}
}
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
from StockSharp.Algo.Strategies import Strategy
class macd_signal_crossover_strategy(Strategy):
"""Simple MACD/signal line crossover strategy. Buys when MACD crosses above signal,
sells when MACD crosses below signal."""
def __init__(self):
super(macd_signal_crossover_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 23) \
.SetDisplay("Fast Period", "Fast EMA period for MACD", "Indicators")
self._slow_period = self.Param("SlowPeriod", 40) \
.SetDisplay("Slow Period", "Slow EMA period for MACD", "Indicators")
self._signal_period = self.Param("SignalPeriod", 8) \
.SetDisplay("Signal Period", "Signal line period for MACD", "Indicators")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Candle type used for analysis", "General")
self._prev_macd_above_signal = False
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 FastPeriod(self):
return self._fast_period.Value
@property
def SlowPeriod(self):
return self._slow_period.Value
@property
def SignalPeriod(self):
return self._signal_period.Value
def OnReseted(self):
super(macd_signal_crossover_strategy, self).OnReseted()
self._prev_macd_above_signal = False
self._has_prev = False
def OnStarted2(self, time):
super(macd_signal_crossover_strategy, self).OnStarted2(time)
macd = MovingAverageConvergenceDivergenceSignal()
macd.Macd.ShortMa.Length = self.FastPeriod
macd.Macd.LongMa.Length = self.SlowPeriod
macd.SignalMa.Length = self.SignalPeriod
subscription = self.SubscribeCandles(self.CandleType)
subscription.BindEx(macd, self._process_candle).Start()
def _process_candle(self, candle, macd_value):
if candle.State != CandleStates.Finished:
return
if not macd_value.IsFinal:
return
macd_line = macd_value.Macd
signal_line = macd_value.Signal
if macd_line is None or signal_line is None:
return
is_macd_above_signal = float(macd_line) > float(signal_line)
if not self._has_prev:
self._has_prev = True
self._prev_macd_above_signal = is_macd_above_signal
return
crossed_above = is_macd_above_signal and not self._prev_macd_above_signal
crossed_below = not is_macd_above_signal and self._prev_macd_above_signal
if crossed_above:
if self.Position < 0:
self.BuyMarket()
if self.Position <= 0:
self.BuyMarket()
elif crossed_below:
if self.Position > 0:
self.SellMarket()
if self.Position >= 0:
self.SellMarket()
self._prev_macd_above_signal = is_macd_above_signal
def CreateClone(self):
return macd_signal_crossover_strategy()