第 4 章 · 04 自定义与追踪止损 本节摘要:第 3 章第 04 节的 是「静态止损」——固定不动,只能兜底。freqtrade 提供两类「会动的」止损:追踪止损(trailing stop,纯配置驱动,价格涨止损跟着涨)与自定义止损回调( ,纯代码驱动,任意复杂逻辑)。本节讲透这两种机制:trailing 的四个配置参数( / / / )如何组合出「保本止损 → 盈利后紧追」的策略; 的返回值语义(相对当前价的距离)与三个实战例子(保本位、阶梯锁利、基于 ATR 的波动率止损);以及「止损挂在交易所」( )的取舍。读完本节,你能为策略配出专业级的「让利润奔跑,同时锁定收益」出场逻辑。 内容来源:原项目文档 、 ,汉化并套用体系化模板。
本节摘要:第 3 章第 04 节的
stoploss = -0.10是「静态止损」——固定不动,只能兜底。freqtrade 提供两类「会动的」止损:追踪止损(trailing stop,纯配置驱动,价格涨止损跟着涨)与自定义止损回调(custom_stoploss,纯代码驱动,任意复杂逻辑)。本节讲透这两种机制:trailing 的四个配置参数(trailing_stop/trailing_stop_positive/trailing_stop_positive_offset/trailing_only_offset_is_reached)如何组合出「保本止损 → 盈利后紧追」的策略;custom_stoploss的返回值语义(相对当前价的距离)与三个实战例子(保本位、阶梯锁利、基于 ATR 的波动率止损);以及「止损挂在交易所」(stoploss_on_exchange)的取舍。读完本节,你能为策略配出专业级的「让利润奔跑,同时锁定收益」出场逻辑。
内容来源:原项目文档
docs/stoploss.md、docs/strategy-callbacks.md,汉化并套用体系化模板。
⚠️ 风险提示:追踪止损在剧烈波动行情下可能「被洗下车」——价格瞬间下探触发止损,然后立即反弹,你卖在最低点。配置时要在「锁利」与「呼吸空间」间取舍,务必回测多种参数。
阅读完本节,你应当能够:
trailing_stop_positive_offset 与 minimal_roi 的协同。custom_stoploss,理解返回值是相对当前价的距离。stoploss_from_open / stoploss_from_absolute 辅助函数做转换。stoploss_on_exchange(挂交易所)的利弊。| 模式 | 触发方式 | 配置/代码 | 适合 |
|---|---|---|---|
| 静态止损 | 亏到固定比例 | stoploss = -0.10 |
新手、兜底 |
| 追踪止损(trailing) | 价格涨,止损跟着涨 | trailing_stop = True + 三参数 |
趋势跟随、自动锁利 |
自定义止损(custom_stoploss) |
任意逻辑 | 重写回调方法 | 复杂逻辑(ATR、阶梯、保本) |
三者叠加生效:引擎每轮取「最紧的(最接近当前价)」止损作为实际止损。所以你可以同时配静态 -0.10 兜底、trailing 跟随、custom 做复杂判断——三道保险。
最简单的 trailing——开 -0.10 后,只要价格涨,止损就跟着涨 10%:
stoploss = -0.10 trailing_stop = True
但这有个问题:涨 1% 后回撤,止损也跟着上移到「当前价 -10%」,很可能在还没真正盈利时就被洗出。要解决,引入「正止损」与「偏移」:
stoploss = -0.10 # 初始止损 10%(亏损时用) trailing_stop = True trailing_stop_positive = 0.02 # 盈利后用 2% 紧追踪 trailing_stop_positive_offset = 0.03 # 浮盈达 3% 才切换到 positive trailing_only_offset_is_reached = True # 严格:未达 offset 不开始追踪
逐参数解读:
| 参数 | 含义 |
|---|---|
stoploss |
未盈利时的止损距离(相对入场价,负数) |
trailing_stop |
是否启用追踪 |
trailing_stop_positive |
盈利后的止损距离(相对最高价,正数表示「最高价 − 2%」) |
trailing_stop_positive_offset |
浮盈达到此比例后,切换到 trailing_stop_positive |
trailing_only_offset_is_reached |
True=严格(未达 offset 不追踪);False=宽松(超过入场价就开始追踪) |
入场价 100,stoploss=-0.10、trailing_stop_positive=0.02、offset=0.03、only_offset=True:
| 阶段 | 价格 | 浮盈 | 当前止损价 | 说明 |
|---|---|---|---|---|
| 入场 | 100 | 0% | 90 | 用初始 -10% |
| 涨 | 102 | 2% | 90 | 未达 3% offset,止损不动 |
| 涨过 offset | 103.5 | 3.5% | 101.43 | 切换到 positive,= 103.5 × (1−0.02) |
| 再涨 | 105 | 5% | 102.9 | 跟着最高价上移 |
| 回撤 | 104 | 4% | 102.9 | 止损只上不下,保持 102.9 |
| 继续跌 | 102.9 | 2.9% | 102.9 | 触及,平仓,锁定 ~2.9% 利润 |
💡 核心心法:trailing 的本质是「承认你猜不准顶」——不预测最高点,而是让市场告诉你「涨不动了」就锁利走人。代价是在震荡市被频繁洗出。
⚠️ 常见坑:如果
trailing_stop_positive_offset>minimal_roi,ROI 会先触发,你的 trailing 还没启动就被 ROI 平仓了。确保offset< 最低 ROI 门槛。
例:ROI 是 {"0": 0.04}(4% 就平),你的 trailing offset 设了 5%——永远到不了 5%,因为 4% 就被 ROI 平了。要么把 ROI 调高({"0": 0.08}),要么把 offset 调低(0.02)。
签名(第 02 节已给):
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs) -> float | None:
返回值语义:相对当前价的止损距离(负数)。如返回 -0.05 表示「止损价 = 当前价 × (1 − 0.05)」。None 表示沿用引擎当前止损(可能来自静态/trailing)。
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs): # 浮盈超过 5%,把止损提到开仓价(保本) if current_profit > 0.05: # 用辅助函数:把"开仓价"转成"相对当前价的距离" return stoploss_from_open( open_relative_stop=0.0, # 止损在开仓价 current_profit=current_profit, is_short=trade.is_short, leverage=trade.leverage, ) return None
stoploss_from_open 是 freqtrade 提供的辅助函数——你给「止损相对开仓价的比例」,它算出「等价的、相对当前价的距离」(负数)。这样你不用手算 current_profit 与开仓价的关系。
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs): # 阶梯:浮盈越大,锁定越多 if current_profit > 0.15: target_open_relative = 0.10 # 锁 10% 利 elif current_profit > 0.08: target_open_relative = 0.04 # 锁 4% elif current_profit > 0.04: target_open_relative = 0.0 # 保本 else: return None # 用默认 -10% return stoploss_from_open(target_open_relative, current_profit, is_short=trade.is_short, leverage=trade.leverage)
不同币波动率不同,固定百分比不合理。用 ATR(平均真实波幅)动态调整:
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs): # 从 dataprovider 取最近 K 线 df, _ = self.dp.get_analyzed_dataframe(pair=pair, timeframe=self.timeframe) if df is None or len(df) == 0: return None atr = df["atr"].iloc[-1] # 止损 = 当前价 - 2×ATR(给两倍波幅的呼吸空间) sl_abs = current_rate - 2 * atr # 转成相对当前价的距离 return stoploss_from_absolute( stop_rate=sl_abs, current_rate=current_rate, is_short=trade.is_short, leverage=trade.leverage, )
stoploss_from_absolute 把「绝对止损价」转成「相对当前价的距离」。这两个辅助函数(stoploss_from_open、stoploss_from_absolute)从 freqtrade.strategy 导入。
默认止损是「引擎监控」——freqtrade 每轮迭代检查价格,触发就发市价单。缺点是引擎宕机时止损失效。stoploss_on_exchange = True 把止损单直接挂在交易所:
order_types = { "entry": "limit", "exit": "limit", "stoploss": "market", "stoploss_on_exchange": True, "stoploss_on_exchange_interval": 60, # 多久更新一次挂单 "stoploss_on_exchange_limit_ratio": 0.99, # limit 价相对 stop 价 }
优点:即使你断网,交易所也会执行止损。缺点:
stoploss_on_exchange_interval(默认 60s)控制频率,避免被交易所限流。💡 建议:实盘重要仓位开
stoploss_on_exchange: True,优先用stoploss: market(stop-market 而非 stop-limit),确保触发必成交。
⚠️ 杠杆关键认知:止损比例是相对本金(stake),不是相对名义仓位(name = stake × leverage)。
例子:10x 杠杆,stake 100$,stoploss -10%:
所以 10x 杠杆下,-10% 止损意味着价格反向 1% 就止损。设太紧会让交易没呼吸空间被秒平;设太松则单笔亏损巨大。合约止损要结合 liquidation_price——止损必须比强平价更紧,否则会被强平(额外费用 + 失控)。
实盘运行时,改了 stoploss 配置后用 /reload_config 即可对未触发 trailing 的持仓生效。但有限制:
⚠️ 限制:如果
trailing_stop=True且止损已经被 trailing 调整过(上移过),/reload_config不会把它再调松——止损只上不下是硬规则。要让止损变松,只能平仓重开。
stoploss)、追踪(trailing 四参数)、自定义(custom_stoploss);引擎取最紧者叠加生效。stoploss(初始)、trailing_stop_positive(盈利后用,正数)、trailing_stop_positive_offset(切换阈值)、trailing_only_offset_is_reached(严格/宽松)。offset < 最低 ROI 门槛,否则 ROI 先触发,trailing 失效。stoploss_from_open / stoploss_from_absolute 做转换,实现保本位、阶梯锁利、ATR 波动率止损。下一节,我们看止损之外的另一类持仓微调——
adjust_trade_position做 DCA 加仓与部分平仓,以及订单价格调整。