Diese Hilfsstrategie hängt automatisch schützende Stop-Loss- und Take-Profit-Orders an jede offene Position auf dem konfigurierten Instrument. Sie spiegelt das Verhalten des originalen MetaTrader-Experten "AutoSet SL TP" wider, indem sie die Liste der aktiven Positionen überwacht und die Broker-Abstandsbeschränkungen vor der Registrierung schützender Orders einhält.
Die Strategie eröffnet keine Trades von sich aus. Stattdessen überwacht sie das Volumen, die Richtung und den Ausführungspreis von Positionen, die manuell oder von anderen Strategien erstellt wurden. Sobald eine Long- oder Short-Position erscheint, berechnet der Algorithmus die gewünschten Stop-Loss- und Take-Profit-Niveaus in MetaTrader-Pips, passt die Niveaus an die Freeze- und Stop-Beschränkungen des Handelsplatzes an und sendet dann die entsprechenden marktschützenden Orders. Wenn die Position vollständig geschlossen ist, werden die schützenden Orders automatisch storniert.
Funktionsweise
Abonniert Level1-Daten, um die besten Bid/Ask-Preise zusammen mit optionalen StopLevel- und FreezeLevel-Feldern des Brokers zu empfangen.
Wandelt die konfigurierten Pip-Abstände in absolute Preise um, indem die Symbol-Metadaten (Preisschritt und Dezimalgenauigkeit) verwendet werden. Fünf- und dreistellige Kurse werden automatisch um den Faktor zehn skaliert, um der MetaTrader-Pip-Semantik zu entsprechen.
Bei jeder Kursänderung oder persönlichen Trade-Benachrichtigung:
Ignoriert das Signal, wenn keine offene Position vorhanden ist oder wenn die Richtung nicht dem konfigurierten Filter entspricht (nur Kauf, nur Verkauf oder beide).
Berechnet den minimal zulässigen Abstand zwischen dem Marktpreis und einer Schutz-Order. Wenn der Broker keine Freeze/Stop-Niveaus veröffentlicht, fällt der Algorithmus auf drei Spreads multipliziert mit 1.1 zurück, um sicher außerhalb verbotener Zonen zu bleiben.
Bestimmt den Stop-Loss- und Take-Profit-Preis relativ zum aktuellen Ask (für Longs) oder Bid (für Shorts) und normalisiert das Ergebnis auf den Instrument-Preisschritt.
Platziert oder re-registriert Stop- oder Limit-Schutzorders mit dem genauen Positionsvolumen. Orders werden nur ersetzt, wenn sich der Zielpreis oder das Volumen ändert, was Exchange-Modifikationen minimiert.
Wenn das Positionsvolumen null wird, werden alle ausstehenden Schutzorders storniert. Die Strategie storniert auch bestehende Orders, wenn die Trade-Richtung durch den Filter nicht mehr erlaubt ist.
Da der Algorithmus ausschließlich auf externe Fills angewiesen ist, kann er mit diskretionärem Trading, Panels oder anderen automatisierten Systemen kombiniert werden, die Einträge verwalten, während diese Strategie eine konsistente Schutzhülle garantiert.
Parameter
StopLossPips – Abstand vom aktuellen Marktpreis zum Stop-Loss in MetaTrader-Pips. Ein Wert von 0 deaktiviert die Stop-Order. Standard: 50.
TakeProfitPips – Abstand vom aktuellen Marktpreis zum Take-Profit in MetaTrader-Pips. Ein Wert von 0 deaktiviert die Take-Profit-Order. Standard: 140.
DirectionFilter – gibt an, welche Positionsrichtung verwaltet wird:
Buy – nur Long-Exposure schützen.
Sell – nur Short-Exposure schützen.
BuySell – beide Seiten schützen (Standardverhalten im Originalskript).
Praktische Hinweise
Schutzorders werden immer mit dem absoluten Positionsvolumen erstellt. Wenn der Broker minimale oder maximale Lotgrößen vorschreibt, rundet die Strategie das Volumen auf den nächsten zulässigen Wert, bevor Orders platziert werden.
Der Algorithmus verwendet ReRegisterOrder, um aktive Schutzorders anzupassen. Dies behält nach Möglichkeit dieselben Exchange-Order-Identifier und vermeidet unnötige Stornierungen.
Der Fallback-Abstand (Spread × 3 × 1.1) verhindert, dass der Stop oder Take-Profit versteckte Exchange-Beschränkungen verletzt, wenn keine expliziten Freeze/Stop-Niveaus bereitgestellt werden.
Da die Strategie keine Einträge verwaltet, kann sie vor oder nach dem Eröffnen von Positionen gestartet werden. Jede qualifizierende Position, die zum Zeitpunkt des Starts bereits existiert, wird unmittelbar nach der ersten Kursänderung geschützt.
MetaTrader-„Pips" unterscheiden sich von Exchange-Preisschritten bei Symbolen mit drei oder fünf Dezimalstellen. Die Strategie spiegelt den originalen Expert Advisor, indem sie den Punktwert entsprechend multipliziert, um sicherzustellen, dass die konfigurierten Zahlen genau den MT5-Einstellungen entsprechen.
Unterschiede zum MetaTrader-Experten
Anstatt Stop- und Take-Profit-Attribute in der Position zu modifizieren, verwaltet StockSharp explizite schützende Stop- und Limit-Orders. Dieser Ansatz hält die Logik vollständig transparent im StockSharp-Orderbuch.
Die StockSharp-Version verwendet Level1-Marktdaten, um Broker-Beschränkungsniveaus zu rekonstruieren. Wenn der Anbieter unterschiedliche Feldnamen für Freeze- oder Stop-Abstände bereitstellt, entdeckt die Strategie diese automatisch durch Reflexion auf dem Level1Fields-Enum.
Jeder Code-Kommentar und jede Log-Nachricht ist auf Englisch, um mit den Kodierungsrichtlinien konsistent zu bleiben, während die Dokumentation für Endbenutzer auf Russisch und Chinesisch lokalisiert ist.
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 AutoSetStopLossTakeProfitStrategy : 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 AutoSetStopLossTakeProfitStrategy()
{
_fastPeriod = Param(nameof(FastPeriod), 14).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 auto_set_stop_loss_take_profit_strategy(Strategy):
def __init__(self):
super(auto_set_stop_loss_take_profit_strategy, self).__init__()
self._fast_period = self.Param("FastPeriod", 14) \
.SetDisplay("Fast Period", "Fast MA period", "Indicator")
self._slow_period = self.Param("SlowPeriod", 50) \
.SetDisplay("Slow Period", "Slow MA 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._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
@property
def fast_period(self):
return self._fast_period.Value
@property
def slow_period(self):
return self._slow_period.Value
@property
def stop_loss_points(self):
return self._stop_loss_points.Value
@property
def take_profit_points(self):
return self._take_profit_points.Value
def OnReseted(self):
super(auto_set_stop_loss_take_profit_strategy, self).OnReseted()
self._fast = None
self._slow = None
self._prev_fast = 0.0
self._prev_slow = 0.0
self._entry_price = 0.0
self._cooldown = 0
def OnStarted2(self, time):
super(auto_set_stop_loss_take_profit_strategy, self).OnStarted2(time)
self._fast = ExponentialMovingAverage()
self._fast.Length = self.fast_period
self._slow = ExponentialMovingAverage()
self._slow.Length = self.slow_period
subscription = self.SubscribeCandles(DataType.TimeFrame(TimeSpan.FromMinutes(5)))
subscription.Bind(self._fast, self._slow, self._process_candle)
subscription.Start()
def _process_candle(self, candle, fast_value, slow_value):
if candle.State != CandleStates.Finished:
return
fast_val = float(fast_value)
slow_val = float(slow_value)
if not self._fast.IsFormed or not self._slow.IsFormed:
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 = 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 > 0 and close <= self._entry_price - self.stop_loss_points * step:
self.SellMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close >= self._entry_price + self.take_profit_points * step:
self.SellMarket()
self._entry_price = 0.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.stop_loss_points > 0 and close >= self._entry_price + self.stop_loss_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
if self.take_profit_points > 0 and close <= self._entry_price - self.take_profit_points * step:
self.BuyMarket()
self._entry_price = 0.0
self._cooldown = 100
self._prev_fast = fast_val
self._prev_slow = slow_val
return
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 auto_set_stop_loss_take_profit_strategy()