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