ProfitLossTrailStrategy ist ein Risikomanagement-Helfer, der aus dem MetaTrader Expert Advisor ProfitLossTrailEA v2.30 konvertiert wurde. Die Strategie erzeugt keine eigenen Einstiege. Stattdessen überwacht sie die aktuell offene Position im konfigurierten Wertpapier und wendet automatisch Schutzausstiege an:
anfängliche Stop-Loss- und Take-Profit-Niveaus;
Trailing-Stop-Management mit optionaler Aktivierungsdistanz und Trailing-Schrittsteuerung;
Break-even-Schutz mit konfigurierbarem Gewinntrigger und Offset;
Möglichkeit, bestehende Schutzlevel zu entfernen, wenn der Trader sie manuell verwalten möchte.
Das Verhalten entspricht eng dem "Basket"-Managementmodus des ursprünglichen EA: Alle Orders derselben Richtung werden als eine Position behandelt, und die Schutzlevel werden bei jeder Exposure-Änderung neu berechnet.
Parameterreferenz
Parameter
Beschreibung
Manage As Basket
Wenn aktiviert (Standard), berechnet jeder Fill in derselben Richtung den durchschnittlichen Einstiegspreis neu und aktualisiert Stop-Loss-/Take-Profit-Niveaus. Deaktivieren Sie das Flag, um die anfänglichen Niveaus nach dem ersten Fill beizubehalten.
Enable Take Profit
Schaltet automatische Take-Profit-Verarbeitung ein oder aus.
Take Profit (pips)
Distanz in Pips zwischen Einstiegspreis und Take-Profit-Ziel.
Enable Stop Loss
Schaltet automatische Stop-Loss-Verarbeitung ein oder aus.
Stop Loss (pips)
Distanz in Pips zwischen Einstiegspreis und anfänglichem Schutz-Stop.
Enable Trailing Stop
Aktiviert dynamisches Stop-Management, sobald die Position im Gewinn ist.
Trailing Activation (pips)
Mindestgewinn in Pips, bevor sich der Trailing Stop bewegen darf. 0 für sofortige Aktivierung.
Trailing Stop (pips)
Basis-Trailing-Distanz in Pips.
Trailing Step (pips)
Zusätzlicher Gewinn, der vor weiterem Nachziehen des Trailing Stops erzielt werden muss.
Enable Break-Even
Aktiviert die Break-even-Routine, die den Stop nach einer Trigger-Distanz in den Gewinn verschiebt.
Break-Even Trigger (pips)
Gewinndistanz, die die Break-even-Bewegung aktiviert.
Break-Even Offset (pips)
Zusätzlicher Offset oberhalb (Long) oder unterhalb (Short) des Einstiegspreises bei Break-even-Aktivierung.
Remove Take Profit
Wenn auf true gesetzt, wird jeder aktuelle Take-Profit-Wert gelöscht und keine Take-Profit-Ausstiege werden ausgegeben.
Remove Stop Loss
Wenn auf true gesetzt, wird jeder aktuelle Stop-Loss-Wert gelöscht und keine Stop-Loss- oder Trailing-Ausstiege werden ausgegeben.
Candle Type
Kerzenserie zur Überwachung der Preisbewegung. Trailing-, Break-even- und Ausstiegsprüfungen werden auf abgeschlossenen Kerzen bewertet.
Nutzungshinweise
Binden Sie die Strategie an ein Wertpapier und stellen Sie sicher, dass Orders extern oder durch eine andere Strategie platziert werden. ProfitLossTrailStrategy konzentriert sich nur auf die Verwaltung der offenen Exposure.
Konfigurieren Sie die pipbasierten Parameter passend zur Preisstellung des Instruments. Die Pip-Größe wird automatisch aus Security.PriceStep abgeleitet.
Wenn Break-even und Trailing Stop beide aktiviert sind, erfolgt die Break-even-Anpassung zuerst. Nachfolgende Trailing-Schritte ziehen den Stop nur enger, wenn das neue Niveau den aktuellen Schutzpreis mindestens um die angegebene Trailing-Schritt-Distanz verbessert.
Remove Stop Loss deaktiviert Stop-Loss-, Trailing- und Break-even-Logik gleichzeitig und spiegelt damit das Verhalten des ursprünglichen EA.
Die Strategie verwendet Marktorders (BuyMarket/SellMarket), um Positionen zu schließen, wenn Schutzlevel erreicht werden.
Hinweise zur Umstellung
Die MetaTrader-Modi "Order_By_Order" und "Same_Type_As_One" werden durch das Flag Manage As Basket dargestellt. Stop-Level pro Ticket werden in StockSharp nicht unterstützt, daher wird Basket-Modus standardmäßig angewendet.
Magic-Number- und Kommentarfilter aus dem ursprünglichen EA sind nicht erforderlich; die Strategie wirkt nur auf das konfigurierte Strategy.Security.
Bildschirmzeichnung, Tonalarme und timerbasierte UI-Aktualisierungen wurden weggelassen, da StockSharp Diagnosen bereits über Logs und Chart-Bindings bereitstellt.
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 ProfitLossTrailStrategy : 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 ProfitLossTrailStrategy()
{
_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 profit_loss_trail_strategy(Strategy):
def __init__(self):
super(profit_loss_trail_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(profit_loss_trail_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(profit_loss_trail_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 profit_loss_trail_strategy()