Die Trailing Stop Trigger Manager-Strategie ist eine StockSharp-Portierung des MetaTrader-Expertenberaters Trailing Sl.mq5. Das Original EA
hat keine Geschäfte selbstständig eröffnet. Stattdessen überwachte es bereits offene Positionen mit einer passenden magischen Zahl und verschärfte diese
Stop-Loss-Level, wenn sich der Markt in die gewünschte Richtung bewegt. Diese C#-Implementierung reproduziert dieses Verhalten mithilfe von
Die High-Level-Strategie API von StockSharp bietet ein transparentes Trailing-Stop-Management, das mit jedem von unterstützten Instrument funktioniert
StockSharp.
Nachgestellte Logik
Abonniert das Orderbuch, um die neuesten besten Geld- und Briefkurse zu lesen.
Erkennt, ob die Strategie derzeit eine Long- oder Short-Nettoposition hält.
Berechnet den variablen Gewinn anhand der entsprechenden Marktseite (bester Geldkurs für Long-Positionen, bester Briefkurs für Shorts-Positionen).
Aktiviert den Trailing-Modus, sobald der Gewinn TriggerPoints übersteigt (umgerechnet in Preiseinheiten bis PriceStep).
Setzt den Trailing Stop auf den konfigurierten Abstand TrailingPoints vom aktuellen Marktkurs.
Verschiebt den Trailing Stop nur in Richtung Markt, um weiterhin zusätzlichen Gewinn zu erzielen.
Sendet eine Marktorder, um die Position zu glätten, sobald der beste Kurs das berechnete Trailing-Stop-Level berührt.
Auftrags- und Risikomanagement
Die Strategie übermittelt keine Ersteintrittsaufträge. Es verwaltet lediglich eine bestehende Position, die ggf. manuell eröffnet wurde
oder durch eine andere Strategie.
Marktaustritte werden mit BuyMarket/SellMarket platziert und spiegeln die PositionModify-Aufrufe aus dem ursprünglichen MetaTrader-Code wider.
Der Stoppabstand skaliert automatisch mit dem PriceStep des Instruments, wodurch die punktbasierte Konfiguration erhalten bleibt
der EA.
Sobald die Position geschlossen ist, wird der Trailing-Status zurückgesetzt, sodass neue Positionen von vorne beginnen.
Parameter
Name
Typ
Standard
Beschreibung
TrailingPoints
int
1000
Abstand zwischen dem aktuellen Preis und dem Trailing Stop, gemessen in Preisschritten.
TriggerPoints
int
1500
Mindestgewinn in Preisschritten, der erforderlich ist, um mit dem Nachlaufen der Position zu beginnen.
Nutzungshinweise
Hängen Sie die Strategie dem Wertpapier an, dessen Position Sie überwachen möchten. Es beginnt sofort mit der Verfolgung des Vorhandenen
Belichtung.
Konfigurieren Sie den anfänglichen Volume der Strategie so, dass er der Größe Ihrer offenen Position entspricht. StockSharp verwendet Nettopositionen, also
Die Strategie verlässt das gesamte Lot, wenn der Trailing Stop ausgelöst wird.
Wenn der Broker grobe Preissprünge liefert, passen Sie TrailingPoints und TriggerPoints entsprechend an, um vorzeitige Ausstiege zu vermeiden.
Die Strategie behält ihren Status vollständig in StockSharp, sodass sie mit jedem beliebigen diskretionären oder automatisierten System kombiniert werden kann
überlässt die eigentliche Auftragsausführung StockSharp.
Unterschiede zum ursprünglichen MetaTrader-Experten
MetaTrader verwaltete separate Positionen pro Ticket und filterte sie nach magischer Zahl. StockSharp arbeitet mit einer Nettoposition pro
Sicherheit, wodurch die Notwendigkeit einer Ticketfilterung entfällt.
Die Eingänge Setloss, TakeProfit und Lots wurden im ursprünglichen EA nicht verwendet. Sie werden daher im StockSharp weggelassen.
Version, um die Konfiguration auf das Nachlaufverhalten zu konzentrieren.
Auftragsänderungen werden durch direkte Marktaustritte ersetzt, was der idiomatische Ansatz für Netting-Konten in StockSharp ist.
using System;
using System.Linq;
using System.Collections.Generic;
using Ecng.Common;
using Ecng.Collections;
using Ecng.Serialization;
using StockSharp.Algo.Indicators;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Strategy that mirrors the MetaTrader "Trailing Sl" expert by managing trailing stops for existing positions.
/// Adds SMA crossover entries for backtesting.
/// </summary>
public class TrailingStopTriggerManagerStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<int> _trailingPoints;
private readonly StrategyParam<int> _triggerPoints;
private decimal _lastEntryPrice;
private decimal? _activeStopPrice;
private bool _trailingEnabled;
private decimal _trailingDistance;
private decimal _triggerDistance;
private decimal _prevFast;
private decimal _prevSlow;
private bool _hasPrev;
/// <summary>
/// Candle type.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
/// <summary>
/// Trailing stop distance in price steps.
/// </summary>
public int TrailingPoints
{
get => _trailingPoints.Value;
set => _trailingPoints.Value = value;
}
/// <summary>
/// Profit distance that activates trailing stop.
/// </summary>
public int TriggerPoints
{
get => _triggerPoints.Value;
set => _triggerPoints.Value = value;
}
/// <summary>
/// Initializes a new instance of the strategy.
/// </summary>
public TrailingStopTriggerManagerStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(1).TimeFrame())
.SetDisplay("Candle Type", "Timeframe", "General");
_trailingPoints = Param(nameof(TrailingPoints), 1000)
.SetGreaterThanZero()
.SetDisplay("Trailing Points", "Trailing stop distance", "Trailing Management");
_triggerPoints = Param(nameof(TriggerPoints), 1500)
.SetGreaterThanZero()
.SetDisplay("Trigger Points", "Profit to activate trailing", "Trailing Management");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
{
return [(Security, CandleType)];
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_lastEntryPrice = 0m;
_activeStopPrice = null;
_trailingEnabled = false;
_trailingDistance = 0m;
_triggerDistance = 0m;
_prevFast = 0m;
_prevSlow = 0m;
_hasPrev = false;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
var step = Security?.PriceStep ?? 1m;
if (step <= 0m) step = 1m;
_trailingDistance = step * TrailingPoints;
_triggerDistance = step * TriggerPoints;
var smaFast = new SimpleMovingAverage { Length = 10 };
var smaSlow = new SimpleMovingAverage { Length = 30 };
var subscription = SubscribeCandles(CandleType);
subscription
.Bind(smaFast, smaSlow, ProcessCandle)
.Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
_lastEntryPrice = trade.Trade.Price;
}
private void ProcessCandle(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
var price = candle.ClosePrice;
// Trailing stop management
if (Position > 0 && _lastEntryPrice > 0)
{
var profit = price - _lastEntryPrice;
if (!_trailingEnabled && profit >= _triggerDistance)
{
_trailingEnabled = true;
_activeStopPrice = price - _trailingDistance;
}
else if (_trailingEnabled)
{
var desiredStop = price - _trailingDistance;
if (!_activeStopPrice.HasValue || desiredStop > _activeStopPrice.Value)
_activeStopPrice = desiredStop;
}
if (_trailingEnabled && _activeStopPrice.HasValue && price <= _activeStopPrice.Value)
{
SellMarket();
ResetTrailingState();
return;
}
}
else if (Position < 0 && _lastEntryPrice > 0)
{
var profit = _lastEntryPrice - price;
if (!_trailingEnabled && profit >= _triggerDistance)
{
_trailingEnabled = true;
_activeStopPrice = price + _trailingDistance;
}
else if (_trailingEnabled)
{
var desiredStop = price + _trailingDistance;
if (!_activeStopPrice.HasValue || desiredStop < _activeStopPrice.Value)
_activeStopPrice = desiredStop;
}
if (_trailingEnabled && _activeStopPrice.HasValue && price >= _activeStopPrice.Value)
{
BuyMarket();
ResetTrailingState();
return;
}
}
// SMA crossover entries
if (_hasPrev)
{
var crossUp = _prevFast <= _prevSlow && fast > slow;
var crossDown = _prevFast >= _prevSlow && fast < slow;
if (crossUp && Position <= 0)
{
if (Position < 0)
BuyMarket();
BuyMarket();
ResetTrailingState();
}
else if (crossDown && Position >= 0)
{
if (Position > 0)
SellMarket();
SellMarket();
ResetTrailingState();
}
}
_prevFast = fast;
_prevSlow = slow;
_hasPrev = true;
}
private void ResetTrailingState()
{
_trailingEnabled = false;
_activeStopPrice = null;
}
}
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 SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
class trailing_stop_trigger_manager_strategy(Strategy):
def __init__(self):
super(trailing_stop_trigger_manager_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(1))) \
.SetDisplay("Candle Type", "Timeframe", "General")
self._trailing_points = self.Param("TrailingPoints", 1000) \
.SetGreaterThanZero() \
.SetDisplay("Trailing Points", "Trailing stop distance", "Trailing Management")
self._trigger_points = self.Param("TriggerPoints", 1500) \
.SetGreaterThanZero() \
.SetDisplay("Trigger Points", "Profit to activate trailing", "Trailing Management")
self._last_entry_price = 0.0
self._active_stop_price = None
self._trailing_enabled = False
self._trailing_distance = 0.0
self._trigger_distance = 0.0
self._prev_fast = 0.0
self._prev_slow = 0.0
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 TrailingPoints(self):
return self._trailing_points.Value
@TrailingPoints.setter
def TrailingPoints(self, value):
self._trailing_points.Value = value
@property
def TriggerPoints(self):
return self._trigger_points.Value
@TriggerPoints.setter
def TriggerPoints(self, value):
self._trigger_points.Value = value
def OnReseted(self):
super(trailing_stop_trigger_manager_strategy, self).OnReseted()
self._last_entry_price = 0.0
self._active_stop_price = None
self._trailing_enabled = False
self._trailing_distance = 0.0
self._trigger_distance = 0.0
self._prev_fast = 0.0
self._prev_slow = 0.0
self._has_prev = False
def OnStarted2(self, time):
super(trailing_stop_trigger_manager_strategy, self).OnStarted2(time)
step = 1.0
if self.Security is not None and self.Security.PriceStep is not None:
s = float(self.Security.PriceStep)
if s > 0:
step = s
self._trailing_distance = step * self.TrailingPoints
self._trigger_distance = step * self.TriggerPoints
sma_fast = SimpleMovingAverage()
sma_fast.Length = 10
sma_slow = SimpleMovingAverage()
sma_slow.Length = 30
subscription = self.SubscribeCandles(self.CandleType)
subscription.Bind(sma_fast, sma_slow, self._process_candle).Start()
def OnOwnTradeReceived(self, trade):
super(trailing_stop_trigger_manager_strategy, self).OnOwnTradeReceived(trade)
self._last_entry_price = float(trade.Trade.Price)
def _process_candle(self, candle, fast, slow):
if candle.State != CandleStates.Finished:
return
price = float(candle.ClosePrice)
fv = float(fast)
sv = float(slow)
# Trailing stop management for long
if self.Position > 0 and self._last_entry_price > 0:
profit = price - self._last_entry_price
if not self._trailing_enabled and profit >= self._trigger_distance:
self._trailing_enabled = True
self._active_stop_price = price - self._trailing_distance
elif self._trailing_enabled:
desired_stop = price - self._trailing_distance
if self._active_stop_price is None or desired_stop > self._active_stop_price:
self._active_stop_price = desired_stop
if self._trailing_enabled and self._active_stop_price is not None and price <= self._active_stop_price:
self.SellMarket()
self._reset_trailing_state()
return
# Trailing stop management for short
elif self.Position < 0 and self._last_entry_price > 0:
profit = self._last_entry_price - price
if not self._trailing_enabled and profit >= self._trigger_distance:
self._trailing_enabled = True
self._active_stop_price = price + self._trailing_distance
elif self._trailing_enabled:
desired_stop = price + self._trailing_distance
if self._active_stop_price is None or desired_stop < self._active_stop_price:
self._active_stop_price = desired_stop
if self._trailing_enabled and self._active_stop_price is not None and price >= self._active_stop_price:
self.BuyMarket()
self._reset_trailing_state()
return
# SMA crossover entries
if self._has_prev:
cross_up = self._prev_fast <= self._prev_slow and fv > sv
cross_down = self._prev_fast >= self._prev_slow and fv < sv
if cross_up and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._reset_trailing_state()
elif cross_down and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._reset_trailing_state()
self._prev_fast = fv
self._prev_slow = sv
self._has_prev = True
def _reset_trailing_state(self):
self._trailing_enabled = False
self._active_stop_price = None
def CreateClone(self):
return trailing_stop_trigger_manager_strategy()