Lacust Stop and BE
该策略演示了一个基础的仓位管理方案,灵感来自原始的 MQL 智能交易系统 lacuststopandbe。
策略在根据最后一根完成的 K 线方向开仓后,会应用以下保护规则:
- 初始止损和止盈按固定价差设置。
- 当浮盈达到
BreakevenGain时,止损移动到开仓价并锁定Breakeven点的利润。 - 当浮盈超过
TrailingStart时,止损按TrailingStop的距离跟随价格移动。 - 价格触及止损或止盈水平时平仓。
参数:
CandleType– 用于计算的 K 线类型。StopLoss– 初始止损距离。TakeProfit– 初始止盈距离。TrailingStart– 启动跟踪止损所需的利润。TrailingStop– 跟踪止损与当前价格的距离。BreakevenGain– 移动止损到保本前所需的利润。Breakeven– 移动到保本后锁定的利润。
该示例使用 StockSharp 的高级 API,可作为移植简单 MQL 交易管理脚本的模板。
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()