# adjust-trade-position 回调函数详细翻译与解释 该回调函数是 Freqtrade 交易策略中用于动态调整持仓的核心功能,需手动开启才能使用,支持通过加仓( DCA 策略)或减仓优化风险与收益,但需注意其对性能的影响及特殊计算规则。 ## 一、基础配置与启用 要使用 `adjust_trade_position()`,必须先在策略类中启用相关配置,否则函数不会被调用。 1. **核心启用参数** - 需在策略类中添加 `position_adjustment_enable = True`,默认值为 `False`(禁用)。 - 启用后,Freqtrade 启动时会显示警告,提示该功能可能影响性能,需合理设计逻辑。 2. **关键限制参数** - `max_entry_position_adjustment`:限制单次交易的额外加仓次数(初始开仓不计入)。 - 默认值为 `-1`,表示无限制。 - 示例设置 `max_entry_position_adjustment = 3`,意味着初始开仓后最多可额外加仓 3 次。 - `max_dca_multiplier`:(常用于 DCA 策略)控制单次交易的总资金占用倍数,需配合 `custom_stake_amount()` 使用,避免初始开仓占用过多资金导致无法加仓。 ## 二、函数作用与调用时机 该函数的核心作用是在交易存续期间动态调整持仓规模,包括加仓和减仓,其调用时机和频率需特别注意,避免引发不必要的重复操作。 1. **核心作用** - 加仓:返回正数(以基础货币计价的金额),对多头仓位触发额外买入,对空头仓位触发额外卖出。 - 减仓:返回负数,对多头仓位触发部分卖出,对空头仓位触发部分买入;返回 `-trade.stake_amount` 时触发全额平仓。 2. **调用时机与频率** - **实盘/模拟盘(dry_run)**:每 `throttle_process_secs` 秒调用一次(默认 5 秒),频率极高。 - **回测(backtesting)**:每个蜡烛周期(`timeframe` 或 `timeframe_detail`)调用一次,与实盘行为存在差异,可能导致回测结果与实盘偏差。 - **特殊场景**:若存在未成交的挂单(买入或卖出),函数会先取消现有挂单,再根据返回值生成新挂单;部分成交的挂单也会被取消并重新计算金额。 ## 三、函数参数说明 函数接收多个与当前交易、市场状态相关的参数,用于判断是否调整及调整幅度,关键参数含义如下: | 参数名 | 类型 | 说明 | | --- | --- | --- | | `trade` | Trade 对象 | 当前交易的完整信息,包括持仓金额(`trade.stake_amount`)、开仓时间(`trade.open_date_utc`)等 | | `current_time` | datetime | 当前时间,用于时间相关逻辑(如“开仓 1 小时后减仓”) | | `current_rate` | float | 当前市场价格,用于计算收益和调整金额 | | `current_profit` | float | 当前收益比率(如 `0.05` 表示 5% 收益,`-0.03` 表示 3% 亏损) | | `min_stake` | float/None | 交易所允许的最小下单金额,返回值需大于此值才有效 | | `max_stake` | float | 最大可下单金额(受钱包余额、交易所限制影响),返回值需小于此值才有效 | | `current_entry_rate` | float | 基于开仓定价规则计算的当前开仓参考价 | | `current_exit_rate` | float | 基于平仓定价规则计算的当前平仓参考价 | ## 四、关键逻辑规则 使用该函数时需严格遵守 Freqtrade 的内置规则,否则调整信号会被忽略,常见规则如下: 1. **加仓规则** - 返回值必须为正数,且在 `min_stake` 与 `max_stake` 之间,否则信号无效。 - 需确保钱包有足够余额,若返回值超过 `max_stake`(可用余额上限),加仓会失败。 - 加仓次数受 `max_entry_position_adjustment` 限制,达到上限后不再接受加仓信号,但仍会检查减仓逻辑。 2. **减仓规则** - 返回值必须为负数,且绝对值不能超过当前持仓金额(`trade.stake_amount`),否则会导致剩余持仓金额为负,信号被忽略。 - 部分减仓金额计算方式:`需减仓的币种数量 = (-返回值) * trade.amount / trade.stake_amount`。 - 示例:持仓 2 个 SHITCOIN/USDT,开仓金额 100 USDT(`trade.stake_amount=100`),若返回 `-50`,则减仓 1 个 SHITCOIN(`50 * 2 / 100 = 1`)。 3. **止损计算规则** - 止损价格始终基于**初始开仓价**计算,而非平均开仓价,即使多次加仓,止损逻辑也不改变。 - 常规止损规则仍适用:止损价格只能上移(收紧),不能下移(放宽)。 ## 五、示例代码解析(DCA 策略) 以下是一个典型的“下跌加仓(DCA)+ 盈利减仓”策略示例,关键逻辑已标注: ```python # 导入默认模块 class DigDeeperStrategy(IStrategy): # 启用持仓调整功能 position_adjustment_enable = True # 宽松止损,为DCA加仓留出空间 stoploss = -0.30 # 最多额外加仓3次(初始开仓+3次加仓,共4次) max_entry_position_adjustment = 3 # 总资金占用倍数(初始开仓+3次加仓的资金总和为初始单的5.5倍) max_dca_multiplier = 5.5 # 初始开仓时计算单次开仓金额(为后续加仓留资金) def custom_stake_amount(self, pair: str, current_time: datetime, current_rate: float, proposed_stake: float, min_stake: float | None, max_stake: float, leverage: float, entry_tag: str | None, side: str, **kwargs) -> float: # 初始开仓金额 = 建议金额 / 总倍数,确保后续加仓有足够资金 return proposed_stake / self.max_dca_multiplier # 核心持仓调整逻辑 def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float | None, max_stake: float, current_entry_rate: float, current_exit_rate: float, current_entry_profit: float, current_exit_profit: float, **kwargs ) -> float | None | tuple[float | None, str | None]: # 1. 若有未成交挂单,先不操作(避免重复取消/挂单) if trade.has_open_orders: return # 2. 盈利5%且未减仓过,卖出一半持仓锁定利润 if current_profit > 0.05 and trade.nr_of_successful_exits == 0: return -(trade.stake_amount / 2), "half_profit_5%" # 返回元组,第二个元素为操作标签 # 3. 亏损小于5%时,不调整(避免频繁加仓) if current_profit > -0.05: return None # 4. 获取K线数据,确保价格未持续下跌时才加仓 dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) last_candle = dataframe.iloc[-1].squeeze() # 最新K线 previous_candle = dataframe.iloc[-2].squeeze() # 上一根K线 if last_candle["close"] < previous_candle["close"]: # 最新K线收盘价低于上一根,不加仓 return None # 5. 计算加仓金额(每次加仓幅度递增25%) filled_entries = trade.select_filled_orders(trade.entry_side) # 已成交的开仓订单 count_of_entries = trade.nr_of_successful_entries # 已成功开仓次数(初始+加仓) try: # 初始开仓金额 = 第一笔成交订单的金额 stake_amount = filled_entries[0].stake_amount_filled # 加仓金额 = 初始金额 * (1 + 已开仓次数 * 0.25),实现递增加仓 stake_amount = stake_amount * (1 + (count_of_entries * 0.25)) return stake_amount, "1/3rd_increase" # 返回加仓金额和标签 except Exception as exception: return None # 计算失败时不操作 return None ``` ### 示例逻辑说明 1. **初始开仓金额控制**:通过 `custom_stake_amount()` 将初始开仓金额设为“建议金额 / 5.5”,预留 4.5 倍资金用于后续 3 次加仓。 2. **盈利减仓**:当收益超过 5% 且未减仓过时,卖出一半持仓,锁定部分利润。 3. **下跌加仓**:仅当亏损超过 5% 且最新 K 线未持续下跌时才加仓,每次加仓金额递增 25%(如初始 100 USDT,第一次加仓 125 USDT,第二次 150 USDT,第三次 175 USDT),总资金占用为 100+125+150+175=550 USDT,即初始单的 5.5 倍。 ## 六、注意事项与性能优化 1. **避免频繁操作** - 实盘每 5 秒调用一次,需在函数内添加严格条件(如“仅当价格下跌 5% 且距离上次加仓 1 小时”),避免重复加仓/减仓导致高额手续费或资金浪费。 - 示例中通过 `trade.has_open_orders` 检查挂单状态,避免取消/挂单循环。 2. **回测与实盘差异** - 回测中每个蜡烛周期仅调用一次,无法模拟实盘“5 秒一次”的高频调整,可能导致回测收益虚高,需在回测后进行实盘小资金验证。 3. **内存与性能** - 每次调整都会生成新订单并附加到 `trade` 对象中,长期持仓且多次调整会占用大量内存,建议定期平仓(如盈利达目标或持仓超 24 小时),避免性能下降。 4. **与其他函数的配合** - 若使用 DCA 策略,需配合 `custom_stake_amount()` 控制初始开仓金额,否则初始开仓占用全部资金,后续无法加仓。 - 减仓后若需调整止损,可在 `custom_stoploss()` 中处理,但需注意止损仍基于初始开仓价计算。 ## 结尾交付物提议 要不要我帮你整理一份**adjust-trade-position 核心参数与常见错误排查表**?表格会汇总关键参数的使用场景、常见错误(如加仓金额超出限制、减仓导致持仓为负)及解决方案,方便你在实际开发中快速参考。