Estrategia de gestión de Trail SL
Resumen
Trail SL Manager es una estrategia de utilidad que reproduce el comportamiento del experto original MetaTrader trailSL.
No abre operaciones por sí solo. En cambio, supervisa las posiciones existentes y ajusta dinámicamente sus niveles de parada de protección.
La lógica refleja el guión original: primero se presiona el stop para alcanzar el punto de equilibrio una vez que el precio avanza en una cantidad configurable, luego un algoritmo de seguimiento incremental sigue bloqueando las ganancias a medida que continúa la tendencia.
como funciona
- Se suscribe al flujo de velas configurado para monitorear las barras terminadas.
- Realiza un seguimiento del precio de entrada promedio y la dirección de la posición actual.
- Cuando el precio se mueve a favor de la operación en
BreakEvenTriggerPoints, el stop se empuja al precio de entrada más una compensación opcional. - Después de la activación del punto de equilibrio, o inmediatamente si se permite, la estrategia incrementa el stop en
TrailOffsetPointscadaTrailStepPointshasta que el precio se revierta y cierre la posición en el mercado.
Las reglas finales se calculan con la misma aritmética basada en puntos que la versión MetaTrader, por lo que el comportamiento sigue siendo familiar para los operadores que migran a StockSharp.
Parámetros
| Nombre | Descripción | Predeterminado |
|---|---|---|
EnableBreakEven |
Permite mover el stop para alcanzar el punto de equilibrio una vez que la operación se vuelve rentable. | true |
BreakEvenTriggerPoints |
Distancia de beneficio en puntos necesaria para activar el movimiento de equilibrio. | 20 |
BreakEvenOffsetPoints |
Se agregan puntos adicionales al precio de entrada cuando se ejecuta el punto de equilibrio. | 10 |
EnableTrailing |
Alterna la lógica del trailing stop. | true |
TrailAfterBreakEven |
Si es true, el seguimiento comienza solo después del ajuste del punto de equilibrio. |
true |
TrailStartPoints |
Se permite un beneficio mínimo en puntos antes del seguimiento. | 40 |
TrailStepPoints |
Paso de beneficio entre recálculos finales. | 10 |
TrailOffsetPoints |
Puntos agregados a la parada en cada paso final. | 10 |
InitialStopPoints |
Distancia del tope de protección inicial cuando aparece una nueva posición. | 200 |
CandleType |
Suscripción de velas utilizada para monitorear los cambios de precios. | 1 Minute |
Uso
- Adjunte la estrategia a un entorno donde las entradas se generen mediante otra estrategia o manualmente.
- Configure los umbrales basados en puntos para que coincidan con la volatilidad del símbolo y los requisitos del corredor.
- Inicie la estrategia para que pueda monitorear las velas terminadas y ajustar las paradas automáticamente.
- Supervise los dibujos del gráfico para ver cómo evolucionan los niveles de parada con cada paso final.
Nota: La estrategia cierra posiciones con órdenes de mercado cuando se supera el trailing stop simulado. Agregue protección específica del intercambio (como órdenes stop reales) si su flujo de trabajo lo requiere.
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()