myTestFreqAI/doc/adjust_trade_position.md
2025-10-17 19:09:35 +00:00

9.8 KiB
Raw Permalink Blame History

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:每个蜡烛周期(timeframetimeframe_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_stakemax_stake 之间,否则信号无效。
    • 需确保钱包有足够余额,若返回值超过 max_stake(可用余额上限),加仓会失败。
    • 加仓次数受 max_entry_position_adjustment 限制,达到上限后不再接受加仓信号,但仍会检查减仓逻辑。
  2. 减仓规则

    • 返回值必须为负数,且绝对值不能超过当前持仓金额(trade.stake_amount),否则会导致剩余持仓金额为负,信号被忽略。
    • 部分减仓金额计算方式:需减仓的币种数量 = -返回值) * trade.amount / trade.stake_amount
      • 示例:持仓 2 个 SHITCOIN/USDT开仓金额 100 USDTtrade.stake_amount=100),若返回 -50,则减仓 1 个 SHITCOIN50 * 2 / 100 = 1)。
  3. 止损计算规则

    • 止损价格始终基于初始开仓价计算,而非平均开仓价,即使多次加仓,止损逻辑也不改变。
    • 常规止损规则仍适用:止损价格只能上移(收紧),不能下移(放宽)。

五、示例代码解析DCA 策略)

以下是一个典型的“下跌加仓DCA+ 盈利减仓”策略示例,关键逻辑已标注:

# 导入默认模块
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 核心参数与常见错误排查表?表格会汇总关键参数的使用场景、常见错误(如加仓金额超出限制、减仓导致持仓为负)及解决方案,方便你在实际开发中快速参考。