Lacust Stop and BE
This strategy demonstrates basic position management inspired by the original MQL expert advisor lacuststopandbe.
After entering a position in the direction of the last finished candle the strategy applies several protective rules:
- Initial stop loss and take profit are placed at fixed price distances.
- When profit reaches
BreakevenGain, the stop is moved to entry price plusBreakeven. - After profit exceeds
TrailingStart, the stop trails behind price byTrailingStop. - The position is closed when the stop level or take profit level is touched.
Parameters:
CandleType– candle series used for processing.StopLoss– initial stop loss distance.TakeProfit– initial take profit distance.TrailingStart– profit required to activate trailing stop.TrailingStop– trailing stop distance from current price.BreakevenGain– profit required before moving stop to break-even.Breakeven– profit locked after moving stop to break-even.
This sample uses the high level StockSharp API and can serve as a template for porting simple MQL trade management scripts.
using System;
using System.Collections.Generic;
using Ecng.Common;
using StockSharp.Algo.Strategies;
using StockSharp.BusinessEntities;
using StockSharp.Messages;
namespace StockSharp.Samples.Strategies;
/// <summary>
/// Trade management strategy with break-even and trailing stop logic.
/// Enters on candle direction, manages with SL/TP/trailing/breakeven.
/// </summary>
public class LacustStopAndBeStrategy : Strategy
{
private readonly StrategyParam<DataType> _candleType;
private readonly StrategyParam<decimal> _stopLoss;
private readonly StrategyParam<decimal> _takeProfit;
private readonly StrategyParam<decimal> _trailingStart;
private readonly StrategyParam<decimal> _trailingStop;
private readonly StrategyParam<decimal> _breakevenGain;
private readonly StrategyParam<decimal> _breakeven;
private decimal _entryPrice;
private decimal _stopPrice;
private decimal _takePrice;
public DataType CandleType { get => _candleType.Value; set => _candleType.Value = value; }
public decimal StopLoss { get => _stopLoss.Value; set => _stopLoss.Value = value; }
public decimal TakeProfit { get => _takeProfit.Value; set => _takeProfit.Value = value; }
public decimal TrailingStart { get => _trailingStart.Value; set => _trailingStart.Value = value; }
public decimal TrailingStop { get => _trailingStop.Value; set => _trailingStop.Value = value; }
public decimal BreakevenGain { get => _breakevenGain.Value; set => _breakevenGain.Value = value; }
public decimal Breakeven { get => _breakeven.Value; set => _breakeven.Value = value; }
public LacustStopAndBeStrategy()
{
_candleType = Param(nameof(CandleType), TimeSpan.FromHours(4).TimeFrame())
.SetDisplay("Candle type", "Candle type", "General");
_stopLoss = Param(nameof(StopLoss), 400m)
.SetDisplay("Stop loss", "Stop loss distance", "Risk");
_takeProfit = Param(nameof(TakeProfit), 2000m)
.SetDisplay("Take profit", "Take profit distance", "Risk");
_trailingStart = Param(nameof(TrailingStart), 300m)
.SetDisplay("Trailing start", "Profit to activate trailing", "Risk");
_trailingStop = Param(nameof(TrailingStop), 200m)
.SetDisplay("Trailing stop", "Trailing stop distance", "Risk");
_breakevenGain = Param(nameof(BreakevenGain), 250m)
.SetDisplay("Breakeven gain", "Profit for breakeven move", "Risk");
_breakeven = Param(nameof(Breakeven), 100m)
.SetDisplay("Breakeven", "Profit locked at breakeven", "Risk");
}
/// <inheritdoc />
public override IEnumerable<(Security sec, DataType dt)> GetWorkingSecurities()
=> [(Security, CandleType)];
/// <inheritdoc />
protected override void OnReseted()
{
base.OnReseted();
_entryPrice = 0;
_stopPrice = 0;
_takePrice = 0;
}
/// <inheritdoc />
protected override void OnStarted2(DateTime time)
{
base.OnStarted2(time);
SubscribeCandles(CandleType)
.Bind(ProcessCandle)
.Start();
}
private void ProcessCandle(ICandleMessage candle)
{
if (candle.State != CandleStates.Finished)
return;
if (Position == 0)
{
if (candle.ClosePrice > candle.OpenPrice)
{
BuyMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice - StopLoss;
_takePrice = _entryPrice + TakeProfit;
}
else if (candle.ClosePrice < candle.OpenPrice)
{
SellMarket();
_entryPrice = candle.ClosePrice;
_stopPrice = _entryPrice + StopLoss;
_takePrice = _entryPrice - TakeProfit;
}
return;
}
if (Position > 0)
{
if (candle.ClosePrice - _entryPrice >= BreakevenGain && _stopPrice < _entryPrice + Breakeven)
_stopPrice = _entryPrice + Breakeven;
if (candle.ClosePrice - _entryPrice >= TrailingStart && _stopPrice < candle.ClosePrice - TrailingStop)
_stopPrice = candle.ClosePrice - TrailingStop;
if (candle.LowPrice <= _stopPrice || candle.HighPrice >= _takePrice)
{
SellMarket();
}
}
else if (Position < 0)
{
if (_entryPrice - candle.ClosePrice >= BreakevenGain && _stopPrice > _entryPrice - Breakeven)
_stopPrice = _entryPrice - Breakeven;
if (_entryPrice - candle.ClosePrice >= TrailingStart && _stopPrice > candle.ClosePrice + TrailingStop)
_stopPrice = candle.ClosePrice + TrailingStop;
if (candle.HighPrice >= _stopPrice || candle.LowPrice <= _takePrice)
{
BuyMarket();
}
}
}
}
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.Strategies import Strategy
class lacust_stop_and_be_strategy(Strategy):
def __init__(self):
super(lacust_stop_and_be_strategy, self).__init__()
self._candle_type = self.Param("CandleType", DataType.TimeFrame(TimeSpan.FromHours(4))) \
.SetDisplay("Candle type", "Candle type", "General")
self._stop_loss = self.Param("StopLoss", 400.0) \
.SetDisplay("Stop loss", "Stop loss distance", "Risk")
self._take_profit = self.Param("TakeProfit", 2000.0) \
.SetDisplay("Take profit", "Take profit distance", "Risk")
self._trailing_start = self.Param("TrailingStart", 300.0) \
.SetDisplay("Trailing start", "Profit to activate trailing", "Risk")
self._trailing_stop = self.Param("TrailingStop", 200.0) \
.SetDisplay("Trailing stop", "Trailing stop distance", "Risk")
self._breakeven_gain = self.Param("BreakevenGain", 250.0) \
.SetDisplay("Breakeven gain", "Profit for breakeven move", "Risk")
self._breakeven = self.Param("Breakeven", 100.0) \
.SetDisplay("Breakeven", "Profit locked at breakeven", "Risk")
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
@property
def CandleType(self):
return self._candle_type.Value
@CandleType.setter
def CandleType(self, value):
self._candle_type.Value = value
@property
def StopLoss(self):
return self._stop_loss.Value
@StopLoss.setter
def StopLoss(self, value):
self._stop_loss.Value = value
@property
def TakeProfit(self):
return self._take_profit.Value
@TakeProfit.setter
def TakeProfit(self, value):
self._take_profit.Value = value
@property
def TrailingStart(self):
return self._trailing_start.Value
@TrailingStart.setter
def TrailingStart(self, value):
self._trailing_start.Value = value
@property
def TrailingStop(self):
return self._trailing_stop.Value
@TrailingStop.setter
def TrailingStop(self, value):
self._trailing_stop.Value = value
@property
def BreakevenGain(self):
return self._breakeven_gain.Value
@BreakevenGain.setter
def BreakevenGain(self, value):
self._breakeven_gain.Value = value
@property
def Breakeven(self):
return self._breakeven.Value
@Breakeven.setter
def Breakeven(self, value):
self._breakeven.Value = value
def OnStarted2(self, time):
super(lacust_stop_and_be_strategy, self).OnStarted2(time)
self.SubscribeCandles(self.CandleType) \
.Bind(self.ProcessCandle) \
.Start()
def ProcessCandle(self, candle):
if candle.State != CandleStates.Finished:
return
close = float(candle.ClosePrice)
open_price = float(candle.OpenPrice)
high = float(candle.HighPrice)
low = float(candle.LowPrice)
sl = float(self.StopLoss)
tp = float(self.TakeProfit)
ts_start = float(self.TrailingStart)
ts_stop = float(self.TrailingStop)
be_gain = float(self.BreakevenGain)
be = float(self.Breakeven)
if self.Position == 0:
if close > open_price:
self.BuyMarket()
self._entry_price = close
self._stop_price = self._entry_price - sl
self._take_price = self._entry_price + tp
elif close < open_price:
self.SellMarket()
self._entry_price = close
self._stop_price = self._entry_price + sl
self._take_price = self._entry_price - tp
return
if self.Position > 0:
if close - self._entry_price >= be_gain and self._stop_price < self._entry_price + be:
self._stop_price = self._entry_price + be
if close - self._entry_price >= ts_start and self._stop_price < close - ts_stop:
self._stop_price = close - ts_stop
if low <= self._stop_price or high >= self._take_price:
self.SellMarket()
elif self.Position < 0:
if self._entry_price - close >= be_gain and self._stop_price > self._entry_price - be:
self._stop_price = self._entry_price - be
if self._entry_price - close >= ts_start and self._stop_price > close + ts_stop:
self._stop_price = close + ts_stop
if high >= self._stop_price or low <= self._take_price:
self.BuyMarket()
def OnReseted(self):
super(lacust_stop_and_be_strategy, self).OnReseted()
self._entry_price = 0.0
self._stop_price = 0.0
self._take_price = 0.0
def CreateClone(self):
return lacust_stop_and_be_strategy()