Diese Strategie portiert den MetaTrader 5 Expertenberater Simple EA MA plus MACD auf die StockSharp High-Level-API. Sie sucht nach einem Ausbruch aus einem "Signal-Balken", der zwei Bedingungen erfüllt: Ein verschobener gleitender Durchschnitt liegt unter/über den Hochs des Balkens, und das MACD-Histogramm hat gerade die Nulllinie gekreuzt. Wenn die nächste Kerze über das Extremum des Signal-Balkens hinaus schließt, tritt die Strategie in die Ausbruchsrichtung ein.
Die Implementierung behält das ursprüngliche EA-Verhalten bei:
Signalerkennung – bei jeder abgeschlossenen Kerze prüft die Strategie den vorherigen Balken. Ein konfigurierbarer gleitender Durchschnitt (Standard LWMA), berechnet auf dem gewählten angewendeten Preis, muss für Longs kleiner als sowohl das vorherige als auch das aktuelle Kerzenhoch sein (größer für Shorts). Gleichzeitig muss die MACD-Hauptlinie zwischen den beiden vorherigen Balken null gekreuzt haben.
Signalbestätigung – sobald ein Signal-Balken gespeichert ist, wartet die Strategie auf die nächste abgeschlossene Kerze. Ein Schluss über dem gespeicherten Hoch löst einen Long-Ausbruch aus; ein Schluss unter dem gespeicherten Tief löst einen Short-Ausbruch aus. Wenn der Preis das Signal durch Schließen innerhalb des Signal-Balkens ungültig macht, wird das Setup abgebrochen.
Positionsmanagement – neu eröffnete Trades erben Stop-Loss-, Take-Profit- und Trailing-Stop-Abstände in Pips. Schutzlevels werden unter Verwendung des PriceStep des Instruments in absolute Preise konvertiert. Instrumente mit drei oder fünf Dezimalstellen erhalten die klassische Forex-Anpassung (step × 10), um MetaTrader-Pip-Definitionen nachzuahmen.
Risikomanagement
Stop-Loss / Take-Profit – optionale Pip-Abstände werden bei jedem Kerzenschluss ausgewertet. Wenn der Markt über den entsprechenden Level hinausdruckt, steigt die Strategie mit einer Market-Order aus.
Trailing-Stop – wenn der Gewinn TrailingStopPips + TrailingStepPips übersteigt, wird eine Trailing-Referenz hinter dem besten erreichten Preis bewegt. Wenn der Preis auf das Trailing-Level zurückfällt, wird die Position geschlossen. Ein Trailing-Schritt von null reaktiviert den Stop bei jedem neuen Extremum.
Flat bei Umkehr – wenn ein entgegengesetzter Ausbruch erscheint, während eine entgegengesetzte Position offen ist, sendet die Strategie eine einzige Market-Order, die groß genug ist, um die bestehende Exposition zu schließen und den neuen Trade in einem Schritt zu eröffnen.
Implementierungshinweise
Der gleitende Durchschnitt unterstützt dieselben Glättungsmethoden und angewendeten Preisoptionen wie MetaTrader (Simple, Exponential, Smoothed, LinearWeighted und Close/Open/High/Low/Median/Typical/Weighted-Preise).
MaShift reproduziert den horizontalen Versatz des MetaTrader-Indikators durch Lesen von Werten aus früheren Balken vor der Auswertung der Ausbruchsregeln.
MACD verwendet den eingebauten MovingAverageConvergenceDivergence-Indikator. Nur das Histogramm (Differenz zwischen schnellen und langsamen EMAs) wird benötigt; die Signallinienperiode wird für Parität mit den EA-Einstellungen beibehalten.
Kerzen-Abonnements und Indikatorverarbeitung basieren ausschließlich auf der StockSharp High-Level-API. Kein manuelles Tick-Handling oder Indikatorpuffer werden verwendet.
Parameter
Parameter
Standard
Beschreibung
Volume
1
Ordergröße für jeden Ausbruchseinstieg.
TakeProfitPips
50
Gewinnzielabstand in Pips (umgerechnet in absoluten Preis mit dem Instrument-Preisschritt). Auf 0 setzen zum Deaktivieren.
StopLossPips
50
Schutz-Stop-Abstand in Pips. Auf 0 setzen zum Deaktivieren.
TrailingStopPips
5
Trailing-Stop-Abstand in Pips, der fixiert wird, sobald der Preis ausreichend vorrückt.
TrailingStepPips
5
Minimaler zusätzlicher Fortschritt (in Pips) bevor der Trailing-Stop wieder vorrückt.
MaPeriod
100
Länge des gleitenden Durchschnitts zur Validierung des Signal-Balkens.
MaShift
0
Horizontaler Versatz des gleitenden Durchschnitts, emuliert den MetaTrader-Parameter ma_shift.
MaMethod
LinearWeighted
Glättungsmethode des gleitenden Durchschnitts (Simple, Exponential, Smoothed, LinearWeighted).
MaAppliedPrice
Weighted
Preisquelle für den gleitenden Durchschnitt (Close, Open, High, Low, Median, Typical, Weighted).
MacdFastPeriod
12
Schnelle EMA-Periode für die MACD-Berechnung.
MacdSlowPeriod
26
Langsame EMA-Periode für die MACD-Berechnung.
MacdSignalPeriod
9
Signallinien-Glättungsperiode für Parität mit dem ursprünglichen EA.
MacdAppliedPrice
Weighted
Angewendeter Preis beim Einspeisung von Werten in MACD.
CandleType
1 hour time frame
Primäre Kerzenserie für Signale und Trade-Management.
Verwendungstipps
Die Pip-basierten Schutzmaßnahmen an die Tick-Größe des ausgewählten Instruments anpassen; falsche PriceStep-Werte auf der Connector-Seite verzerren die Pip-Konvertierungen.
Für hochvolatile Märkte TrailingStepPips erhöhen, um vorzeitige Ausstiege zu reduzieren, oder verringern, um das Trailing-Verhalten zu verschärfen.
Da Trades auf geschlossenen Kerzen ausgeführt werden, muss der Ausbruch bis zum Balkenabschluss andauern; kleinere Zeitrahmen erhöhen die Handelsfrequenz, können aber mehr Rauschen einführen.
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;
/// <summary>
/// Simple EA MA plus MACD strategy using EMA crossover.
/// Buys when fast EMA crosses above slow EMA, sells on reverse.
/// </summary>
public class SimpleEaMaPlusMacdStrategy : 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 SimpleEaMaPlusMacdStrategy()
{
_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
from datatype_extensions import *
from indicator_extensions import *
class simple_ea_ma_plus_macd_strategy(Strategy):
def __init__(self):
super(simple_ea_ma_plus_macd_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._sl_points = self.Param("StopLossPoints", 200).SetNotNegative().SetDisplay("Stop Loss", "SL in price steps", "Risk")
self._tp_points = self.Param("TakeProfitPoints", 400).SetNotNegative().SetDisplay("Take Profit", "TP in price steps", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle type", "General")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def OnReseted(self):
super(simple_ea_ma_plus_macd_strategy, self).OnReseted()
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
def OnStarted2(self, time):
super(simple_ea_ma_plus_macd_strategy, self).OnStarted2(time)
self._prev_fast = 0
self._prev_slow = 0
self._entry_price = 0
self._cooldown = 0
self._step = 1.0
if self.Security is not None and self.Security.PriceStep is not None and self.Security.PriceStep > 0:
self._step = float(self.Security.PriceStep)
fast = ExponentialMovingAverage()
fast.Length = self._fast_period.Value
slow = ExponentialMovingAverage()
slow.Length = self._slow_period.Value
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
if self._prev_fast == 0 or self._prev_slow == 0:
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._cooldown > 0:
self._cooldown -= 1
self._prev_fast = fast_val
self._prev_slow = slow_val
return
close = float(candle.ClosePrice)
step = self._step
# Manage SL/TP
if self.Position > 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close <= self._entry_price - self._sl_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close >= self._entry_price + self._tp_points.Value * step:
self.SellMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
elif self.Position < 0 and self._entry_price > 0:
if self._sl_points.Value > 0 and close >= self._entry_price + self._sl_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self._tp_points.Value > 0 and close <= self._entry_price - self._tp_points.Value * step:
self.BuyMarket()
self._entry_price = 0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
# Crossover signals
if self._prev_fast <= self._prev_slow and fast_val > slow_val 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_val < slow_val and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._entry_price = close
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
def CreateClone(self):
return simple_ea_ma_plus_macd_strategy()