Trail SL Manager-Strategie
Zusammenfassung
Trail SL Manager ist eine Utility-Strategie, die das Verhalten des ursprünglichen MetaTrader trailSL-Experten reproduziert.
Es eröffnet keine Geschäfte selbst. Stattdessen überwacht es bestehende Positionen und passt deren Schutzstoppniveaus dynamisch an.
Die Logik spiegelt das Quellskript wider: Zuerst wird der Stop gedrückt, um die Gewinnschwelle zu erreichen, sobald der Preis um einen konfigurierbaren Betrag steigt, dann hält ein inkrementeller Trailing-Algorithmus weiterhin Gewinne fest, während der Trend anhält.
Wie es funktioniert
- Abonniert den konfigurierten Kerzenstrom, um fertige Balken zu überwachen.
- Verfolgt den durchschnittlichen Einstiegspreis und die Richtung der aktuellen Position.
- Wenn sich der Preis um
BreakEvenTriggerPointszugunsten des Handels bewegt, wird der Stop auf den Einstiegspreis zuzüglich eines optionalen Offsets verschoben. - Nach der Break-Even-Aktivierung oder sofort, sofern zulässig, erhöht die Strategie den Stop alle
TrailStepPointsumTrailOffsetPoints, bis sich der Preis umkehrt und die Position zum Marktwert schließt.
Die abschließenden Regeln werden mit der gleichen punktbasierten Arithmetik wie die MetaTrader-Version berechnet, sodass das Verhalten für Händler, die auf StockSharp migrieren, vertraut bleibt.
Parameter
| Name | Beschreibung | Standard |
|---|---|---|
EnableBreakEven |
Ermöglicht die Verschiebung des Stops auf die Gewinnschwelle, sobald der Handel profitabel wird. | true |
BreakEvenTriggerPoints |
Gewinnentfernung in Punkten, die erforderlich ist, um die Break-Even-Bewegung zu aktivieren. | 20 |
BreakEvenOffsetPoints |
Zusätzliche Punkte werden dem Einstiegspreis hinzugefügt, wenn die Gewinnschwelle erreicht wird. | 10 |
EnableTrailing |
Schaltet die Trailing-Stop-Logik um. | true |
TrailAfterBreakEven |
Bei true beginnt das Trailing erst nach der Break-Even-Anpassung. |
true |
TrailStartPoints |
Der Mindestgewinn in Punkten vor dem Nachlaufen ist zulässig. | 40 |
TrailStepPoints |
Gewinnschritt zwischen nachlaufenden Neuberechnungen. | 10 |
TrailOffsetPoints |
Bei jedem nachlaufenden Schritt werden dem Stopp Punkte hinzugefügt. | 10 |
InitialStopPoints |
Abstand des anfänglichen Schutzstopps, wenn eine neue Position erscheint. | 200 |
CandleType |
Kerzenabonnement zur Überwachung von Preisänderungen. | 1 Minute |
Nutzung
- Hängen Sie die Strategie an eine Umgebung an, in der Einträge durch eine andere Strategie oder manuell generiert werden.
- Konfigurieren Sie die punktbasierten Schwellenwerte so, dass sie der Symbolvolatilität und den Brokeranforderungen entsprechen.
- Starten Sie die Strategie, damit fertige Kerzen überwacht und Stopps automatisch angepasst werden können.
- Beobachten Sie die Diagrammzeichnungen, um zu sehen, wie sich die Stop-Levels mit jedem nachlaufenden Schritt entwickeln.
Hinweis: Die Strategie schließt Positionen mit Marktaufträgen, wenn der simulierte Trailing Stop durchbrochen wird. Fügen Sie börsenspezifischen Schutz hinzu (z. B. echte Stop-Orders), wenn Ihr Workflow dies erfordert.
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>
/// Utility strategy that mirrors the trailSL MetaTrader script.
/// It manages open positions by moving the protective stop to break even and trailing it as price advances.
/// The strategy does not generate its own entry signals.
/// </summary>
public class TrailSlManagerStrategy : Strategy
{
private readonly StrategyParam<bool> _enableBreakEven;
private readonly StrategyParam<int> _breakEvenTriggerPoints;
private readonly StrategyParam<int> _breakEvenOffsetPoints;
private readonly StrategyParam<bool> _enableTrailing;
private readonly StrategyParam<bool> _trailAfterBreakEven;
private readonly StrategyParam<int> _trailStartPoints;
private readonly StrategyParam<int> _trailStepPoints;
private readonly StrategyParam<int> _trailOffsetPoints;
private readonly StrategyParam<int> _initialStopPoints;
private readonly StrategyParam<DataType> _candleType;
private decimal _priceStep;
private decimal _longStop;
private decimal _shortStop;
private bool _longBreakEvenActive;
private bool _shortBreakEvenActive;
private decimal _lastEntryPrice;
private SimpleMovingAverage _smaFast;
private SimpleMovingAverage _smaSlow;
private int _cooldown;
private int _lastSignal;
/// <summary>
/// Enables automatic break-even adjustment.
/// </summary>
public bool EnableBreakEven
{
get => _enableBreakEven.Value;
set => _enableBreakEven.Value = value;
}
/// <summary>
/// Required profit in points before break-even is activated.
/// </summary>
public int BreakEvenTriggerPoints
{
get => _breakEvenTriggerPoints.Value;
set => _breakEvenTriggerPoints.Value = value;
}
/// <summary>
/// Additional points added to the break-even price once triggered.
/// </summary>
public int BreakEvenOffsetPoints
{
get => _breakEvenOffsetPoints.Value;
set => _breakEvenOffsetPoints.Value = value;
}
/// <summary>
/// Enables trailing stop management.
/// </summary>
public bool EnableTrailing
{
get => _enableTrailing.Value;
set => _enableTrailing.Value = value;
}
/// <summary>
/// Trailing starts only after a successful break-even move.
/// </summary>
public bool TrailAfterBreakEven
{
get => _trailAfterBreakEven.Value;
set => _trailAfterBreakEven.Value = value;
}
/// <summary>
/// Minimum profit in points before trailing begins.
/// </summary>
public int TrailStartPoints
{
get => _trailStartPoints.Value;
set => _trailStartPoints.Value = value;
}
/// <summary>
/// Distance in points between trailing recalculations.
/// </summary>
public int TrailStepPoints
{
get => _trailStepPoints.Value;
set => _trailStepPoints.Value = value;
}
/// <summary>
/// Stop loss increment applied on each trailing step (points).
/// </summary>
public int TrailOffsetPoints
{
get => _trailOffsetPoints.Value;
set => _trailOffsetPoints.Value = value;
}
/// <summary>
/// Initial protective stop distance measured in points.
/// </summary>
public int InitialStopPoints
{
get => _initialStopPoints.Value;
set => _initialStopPoints.Value = value;
}
/// <summary>
/// Candle type used for monitoring price progress.
/// </summary>
public DataType CandleType
{
get => _candleType.Value;
set => _candleType.Value = value;
}
public TrailSlManagerStrategy()
{
_enableBreakEven = Param(nameof(EnableBreakEven), true)
.SetDisplay("Break Even", "Enable break-even stop adjustment", "Risk")
;
_breakEvenTriggerPoints = Param(nameof(BreakEvenTriggerPoints), 20)
.SetDisplay("Break Even Trigger", "Points required before moving to break-even", "Risk")
;
_breakEvenOffsetPoints = Param(nameof(BreakEvenOffsetPoints), 10)
.SetDisplay("Break Even Offset", "Extra points locked when break-even triggers", "Risk")
;
_enableTrailing = Param(nameof(EnableTrailing), true)
.SetDisplay("Trailing", "Enable trailing stop management", "Risk")
;
_trailAfterBreakEven = Param(nameof(TrailAfterBreakEven), true)
.SetDisplay("Trail After Break Even", "Start trailing only after break-even", "Risk")
;
_trailStartPoints = Param(nameof(TrailStartPoints), 40)
.SetDisplay("Trail Start", "Points of profit before trailing is considered", "Risk")
;
_trailStepPoints = Param(nameof(TrailStepPoints), 10)
.SetDisplay("Trail Step", "Price step that triggers a new trailing recalculation", "Risk")
;
_trailOffsetPoints = Param(nameof(TrailOffsetPoints), 10)
.SetDisplay("Trail Offset", "Points added to the stop on every trailing step", "Risk")
;
_initialStopPoints = Param(nameof(InitialStopPoints), 200)
.SetDisplay("Initial Stop", "Initial stop distance used before trailing", "Risk")
;
_candleType = Param(nameof(CandleType), TimeSpan.FromMinutes(5).TimeFrame())
.SetDisplay("Candle Type", "Candle subscription for monitoring", "Data");
}
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
ResetState();
_priceStep = 0;
_longStop = 0;
_shortStop = 0;
_longBreakEvenActive = false;
_shortBreakEvenActive = false;
_lastEntryPrice = 0;
_smaFast = default;
_smaSlow = default;
_cooldown = 0;
_lastSignal = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
_priceStep = Security?.PriceStep ?? 1m;
if (_priceStep <= 0m)
_priceStep = 1m;
_smaFast = new SimpleMovingAverage { Length = 10 };
_smaSlow = new SimpleMovingAverage { Length = 30 };
var subscription = SubscribeCandles(CandleType);
subscription.Bind(_smaFast, _smaSlow, ProcessCandleWithIndicators).Start();
var area = CreateChartArea();
if (area != null)
{
DrawCandles(area, subscription);
DrawOwnTrades(area);
}
}
/// <inheritdoc />
protected override void OnOwnTradeReceived(MyTrade trade)
{
base.OnOwnTradeReceived(trade);
if (Position == 0)
{
ResetState();
return;
}
if (trade.Order.Side == Sides.Buy && Position > 0)
{
_longStop = InitialStopPoints > 0 ? _lastEntryPrice - InitialStopPoints * _priceStep : 0m;
_longBreakEvenActive = false;
}
else if (trade.Order.Side == Sides.Sell && Position < 0)
{
_shortStop = InitialStopPoints > 0 ? _lastEntryPrice + InitialStopPoints * _priceStep : 0m;
_shortBreakEvenActive = false;
}
}
private void ProcessCandleWithIndicators(ICandleMessage candle, decimal fast, decimal slow)
{
if (candle.State != CandleStates.Finished)
return;
if (_cooldown > 0)
{
_cooldown--;
}
else
{
var signal = fast > slow ? 1 : fast < slow ? -1 : 0;
if (signal == 1 && _lastSignal != 1 && Position == 0)
{
BuyMarket();
_lastEntryPrice = candle.ClosePrice;
_lastSignal = 1;
_cooldown = 20;
}
else if (signal == -1 && _lastSignal != -1 && Position == 0)
{
SellMarket();
_lastEntryPrice = candle.ClosePrice;
_lastSignal = -1;
_cooldown = 20;
}
}
ManageLongPosition(candle);
ManageShortPosition(candle);
}
private void ManageLongPosition(ICandleMessage candle)
{
if (Position <= 0)
{
_longStop = 0m;
_longBreakEvenActive = false;
return;
}
var entryPrice = _lastEntryPrice;
if (entryPrice <= 0m)
return;
var currentPrice = candle.ClosePrice;
var profitPoints = (currentPrice - entryPrice) / _priceStep;
if (EnableBreakEven && !_longBreakEvenActive && profitPoints >= BreakEvenTriggerPoints && BreakEvenTriggerPoints > 0)
{
var newStop = BreakEvenOffsetPoints > 0
? entryPrice + BreakEvenOffsetPoints * _priceStep
: entryPrice;
if (newStop < currentPrice)
{
_longStop = Math.Max(_longStop, newStop);
_longBreakEvenActive = true;
}
}
if (!EnableTrailing || TrailOffsetPoints <= 0 || TrailStepPoints <= 0)
return;
var requireBreakEven = TrailAfterBreakEven && EnableBreakEven;
if (requireBreakEven && !_longBreakEvenActive)
return;
var baseStop = requireBreakEven
? (_longStop > 0m ? _longStop : (BreakEvenOffsetPoints > 0 ? entryPrice + BreakEvenOffsetPoints * _priceStep : entryPrice))
: (InitialStopPoints > 0 ? entryPrice - InitialStopPoints * _priceStep : (_longStop > 0m ? _longStop : 0m));
if (baseStop <= 0m)
return;
if (!requireBreakEven && profitPoints < TrailStartPoints)
return;
if (requireBreakEven)
{
var baseDistance = (currentPrice - baseStop) / _priceStep;
if (baseDistance < TrailStartPoints)
return;
}
var startPrice = requireBreakEven
? baseStop + (TrailStartPoints - TrailStepPoints) * _priceStep
: entryPrice + (TrailStartPoints - TrailStepPoints) * _priceStep;
var stepDistance = TrailStepPoints * _priceStep;
if (stepDistance <= 0m)
return;
var openSteps = (currentPrice - startPrice) / stepDistance;
if (openSteps <= 0m)
return;
var stepOpenPrice = (int)Math.Floor(openSteps);
var currentStopSteps = _longStop > baseStop
? (int)Math.Floor((_longStop - baseStop) / (TrailOffsetPoints * _priceStep))
: 0;
if (stepOpenPrice <= currentStopSteps)
return;
var proposedStop = baseStop + stepOpenPrice * TrailOffsetPoints * _priceStep;
var maxStop = candle.LowPrice - _priceStep;
if (proposedStop >= maxStop)
proposedStop = maxStop;
if (proposedStop > _longStop && proposedStop < currentPrice)
_longStop = proposedStop;
if (_longStop > 0m && candle.LowPrice <= _longStop)
SellMarket(Position);
}
private void ManageShortPosition(ICandleMessage candle)
{
if (Position >= 0)
{
_shortStop = 0m;
_shortBreakEvenActive = false;
return;
}
var entryPrice = _lastEntryPrice;
if (entryPrice <= 0m)
return;
var currentPrice = candle.ClosePrice;
var profitPoints = (entryPrice - currentPrice) / _priceStep;
if (EnableBreakEven && !_shortBreakEvenActive && profitPoints >= BreakEvenTriggerPoints && BreakEvenTriggerPoints > 0)
{
var newStop = BreakEvenOffsetPoints > 0
? entryPrice - BreakEvenOffsetPoints * _priceStep
: entryPrice;
if (newStop > currentPrice)
{
_shortStop = _shortStop == 0m ? newStop : Math.Min(_shortStop, newStop);
_shortBreakEvenActive = true;
}
}
if (!EnableTrailing || TrailOffsetPoints <= 0 || TrailStepPoints <= 0)
return;
var requireBreakEven = TrailAfterBreakEven && EnableBreakEven;
if (requireBreakEven && !_shortBreakEvenActive)
return;
var baseStop = requireBreakEven
? (_shortStop > 0m ? _shortStop : (BreakEvenOffsetPoints > 0 ? entryPrice - BreakEvenOffsetPoints * _priceStep : entryPrice))
: (InitialStopPoints > 0 ? entryPrice + InitialStopPoints * _priceStep : (_shortStop > 0m ? _shortStop : 0m));
if (baseStop <= 0m)
return;
if (!requireBreakEven && profitPoints < TrailStartPoints)
return;
if (requireBreakEven)
{
var baseDistance = (baseStop - currentPrice) / _priceStep;
if (baseDistance < TrailStartPoints)
return;
}
var startPrice = requireBreakEven
? baseStop - (TrailStartPoints - TrailStepPoints) * _priceStep
: entryPrice - (TrailStartPoints - TrailStepPoints) * _priceStep;
var stepDistance = TrailStepPoints * _priceStep;
if (stepDistance <= 0m)
return;
var openSteps = (startPrice - currentPrice) / stepDistance;
if (openSteps <= 0m)
return;
var stepOpenPrice = (int)Math.Floor(openSteps);
var currentStopSteps = _shortStop > 0m
? (int)Math.Floor((baseStop - _shortStop) / (TrailOffsetPoints * _priceStep))
: 0;
if (stepOpenPrice <= currentStopSteps)
return;
var proposedStop = baseStop - stepOpenPrice * TrailOffsetPoints * _priceStep;
var minStop = candle.HighPrice + _priceStep;
if (proposedStop <= minStop)
proposedStop = minStop;
if ((_shortStop == 0m || proposedStop < _shortStop) && proposedStop > currentPrice)
_shortStop = proposedStop;
if (_shortStop > 0m && candle.HighPrice >= _shortStop)
BuyMarket(Math.Abs(Position));
}
private void ResetState()
{
_longStop = 0m;
_shortStop = 0m;
_longBreakEvenActive = false;
_shortBreakEvenActive = false;
}
}
import clr
import math
clr.AddReference("StockSharp.Messages")
clr.AddReference("StockSharp.Algo")
clr.AddReference("StockSharp.Algo.Indicators")
clr.AddReference("StockSharp.Algo.Strategies")
from System import TimeSpan, Math
from StockSharp.Messages import DataType, CandleStates, Sides
from StockSharp.Algo.Indicators import SimpleMovingAverage
from StockSharp.Algo.Strategies import Strategy
from datatype_extensions import *
from indicator_extensions import *
class trail_sl_manager_strategy(Strategy):
"""SMA crossover (10/30) with break-even and trailing stop management."""
def __init__(self):
super(trail_sl_manager_strategy, self).__init__()
self._enable_be = self.Param("EnableBreakEven", True).SetDisplay("Break Even", "Enable break-even stop adjustment", "Risk")
self._be_trigger = self.Param("BreakEvenTriggerPoints", 20).SetDisplay("Break Even Trigger", "Points before break-even", "Risk")
self._be_offset = self.Param("BreakEvenOffsetPoints", 10).SetDisplay("Break Even Offset", "Extra points locked at break-even", "Risk")
self._enable_trailing = self.Param("EnableTrailing", True).SetDisplay("Trailing", "Enable trailing stop management", "Risk")
self._trail_after_be = self.Param("TrailAfterBreakEven", True).SetDisplay("Trail After Break Even", "Start trailing only after break-even", "Risk")
self._trail_start = self.Param("TrailStartPoints", 40).SetDisplay("Trail Start", "Points before trailing begins", "Risk")
self._trail_step = self.Param("TrailStepPoints", 10).SetDisplay("Trail Step", "Step for trailing recalculation", "Risk")
self._trail_offset = self.Param("TrailOffsetPoints", 10).SetDisplay("Trail Offset", "SL increment per trailing step", "Risk")
self._initial_stop = self.Param("InitialStopPoints", 200).SetDisplay("Initial Stop", "Initial stop distance", "Risk")
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromMinutes(5))).SetDisplay("Candle Type", "Candle subscription", "Data")
@property
def CandleType(self): return self._candle_type.Value
@CandleType.setter
def CandleType(self, value): self._candle_type.Value = value
def _reset_state(self):
self._long_stop = 0.0
self._short_stop = 0.0
self._long_be_active = False
self._short_be_active = False
def OnReseted(self):
super(trail_sl_manager_strategy, self).OnReseted()
self._reset_state()
def OnStarted2(self, time):
super(trail_sl_manager_strategy, self).OnStarted2(time)
sec = self.Security
ps = 0.0
if sec is not None and sec.PriceStep is not None:
try:
ps = float(sec.PriceStep)
except:
ps = 0.0
self._price_step = ps if ps > 0 else 1.0
self._last_entry_price = 0.0
self._reset_state()
fast = SimpleMovingAverage()
fast.Length = 10
slow = SimpleMovingAverage()
slow.Length = 30
sub = self.SubscribeCandles(self.CandleType)
sub.Bind(fast, slow, self.OnProcess).Start()
area = self.CreateChartArea()
if area is not None:
self.DrawCandles(area, sub)
self.DrawOwnTrades(area)
def OnOwnTradeReceived(self, trade):
super(trail_sl_manager_strategy, self).OnOwnTradeReceived(trade)
if self.Position == 0:
self._reset_state()
return
if trade.Order.Side == Sides.Buy and self.Position > 0:
self._long_stop = self._last_entry_price - self._initial_stop.Value * self._price_step if self._initial_stop.Value > 0 else 0.0
self._long_be_active = False
elif trade.Order.Side == Sides.Sell and self.Position < 0:
self._short_stop = self._last_entry_price + self._initial_stop.Value * self._price_step if self._initial_stop.Value > 0 else 0.0
self._short_be_active = False
def OnProcess(self, candle, fast_val, slow_val):
if candle.State != CandleStates.Finished:
return
fast = float(fast_val)
slow = float(slow_val)
if fast > slow and self.Position <= 0:
if self.Position < 0:
self.BuyMarket()
self.BuyMarket()
self._last_entry_price = float(candle.ClosePrice)
elif fast < slow and self.Position >= 0:
if self.Position > 0:
self.SellMarket()
self.SellMarket()
self._last_entry_price = float(candle.ClosePrice)
self._manage_long(candle)
self._manage_short(candle)
def _manage_long(self, candle):
if self.Position <= 0:
self._long_stop = 0.0
self._long_be_active = False
return
entry_price = self._last_entry_price
if entry_price <= 0:
return
ps = self._price_step
current_price = float(candle.ClosePrice)
profit_points = (current_price - entry_price) / ps
be_trigger = self._be_trigger.Value
be_offset = self._be_offset.Value
if self._enable_be.Value and not self._long_be_active and profit_points >= be_trigger and be_trigger > 0:
new_stop = entry_price + be_offset * ps if be_offset > 0 else entry_price
if new_stop < current_price:
self._long_stop = max(self._long_stop, new_stop)
self._long_be_active = True
trail_offset = self._trail_offset.Value
trail_step = self._trail_step.Value
if not self._enable_trailing.Value or trail_offset <= 0 or trail_step <= 0:
return
require_be = self._trail_after_be.Value and self._enable_be.Value
if require_be and not self._long_be_active:
return
if require_be:
base_stop = self._long_stop if self._long_stop > 0 else (entry_price + be_offset * ps if be_offset > 0 else entry_price)
else:
if self._initial_stop.Value > 0:
base_stop = entry_price - self._initial_stop.Value * ps
else:
base_stop = self._long_stop if self._long_stop > 0 else 0.0
if base_stop <= 0:
return
trail_start = self._trail_start.Value
if not require_be and profit_points < trail_start:
return
if require_be:
base_distance = (current_price - base_stop) / ps
if base_distance < trail_start:
return
if require_be:
start_price = base_stop + (trail_start - trail_step) * ps
else:
start_price = entry_price + (trail_start - trail_step) * ps
step_distance = trail_step * ps
if step_distance <= 0:
return
open_steps = (current_price - start_price) / step_distance
if open_steps <= 0:
return
step_open_price = int(math.floor(open_steps))
if self._long_stop > base_stop:
current_stop_steps = int(math.floor((self._long_stop - base_stop) / (trail_offset * ps)))
else:
current_stop_steps = 0
if step_open_price <= current_stop_steps:
return
proposed_stop = base_stop + step_open_price * trail_offset * ps
max_stop = float(candle.LowPrice) - ps
if proposed_stop >= max_stop:
proposed_stop = max_stop
if proposed_stop > self._long_stop and proposed_stop < current_price:
self._long_stop = proposed_stop
if self._long_stop > 0 and float(candle.LowPrice) <= self._long_stop:
self.SellMarket()
def _manage_short(self, candle):
if self.Position >= 0:
self._short_stop = 0.0
self._short_be_active = False
return
entry_price = self._last_entry_price
if entry_price <= 0:
return
ps = self._price_step
current_price = float(candle.ClosePrice)
profit_points = (entry_price - current_price) / ps
be_trigger = self._be_trigger.Value
be_offset = self._be_offset.Value
if self._enable_be.Value and not self._short_be_active and profit_points >= be_trigger and be_trigger > 0:
new_stop = entry_price - be_offset * ps if be_offset > 0 else entry_price
if new_stop > current_price:
self._short_stop = new_stop if self._short_stop == 0 else min(self._short_stop, new_stop)
self._short_be_active = True
trail_offset = self._trail_offset.Value
trail_step = self._trail_step.Value
if not self._enable_trailing.Value or trail_offset <= 0 or trail_step <= 0:
return
require_be = self._trail_after_be.Value and self._enable_be.Value
if require_be and not self._short_be_active:
return
if require_be:
base_stop = self._short_stop if self._short_stop > 0 else (entry_price - be_offset * ps if be_offset > 0 else entry_price)
else:
if self._initial_stop.Value > 0:
base_stop = entry_price + self._initial_stop.Value * ps
else:
base_stop = self._short_stop if self._short_stop > 0 else 0.0
if base_stop <= 0:
return
trail_start = self._trail_start.Value
if not require_be and profit_points < trail_start:
return
if require_be:
base_distance = (base_stop - current_price) / ps
if base_distance < trail_start:
return
if require_be:
start_price = base_stop - (trail_start - trail_step) * ps
else:
start_price = entry_price - (trail_start - trail_step) * ps
step_distance = trail_step * ps
if step_distance <= 0:
return
open_steps = (start_price - current_price) / step_distance
if open_steps <= 0:
return
step_open_price = int(math.floor(open_steps))
if self._short_stop > 0:
current_stop_steps = int(math.floor((base_stop - self._short_stop) / (trail_offset * ps)))
else:
current_stop_steps = 0
if step_open_price <= current_stop_steps:
return
proposed_stop = base_stop - step_open_price * trail_offset * ps
min_stop = float(candle.HighPrice) + ps
if proposed_stop <= min_stop:
proposed_stop = min_stop
if (self._short_stop == 0 or proposed_stop < self._short_stop) and proposed_stop > current_price:
self._short_stop = proposed_stop
if self._short_stop > 0 and float(candle.HighPrice) >= self._short_stop:
self.BuyMarket()
def CreateClone(self):
return trail_sl_manager_strategy()