Files
wiki/quant/stoploss_leverage_adjustment.md
T

194 lines
8.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 止盈止损策略调整文档
## 一、背景
策略 `MultiAssetChannelBreakoutV5` 运行在 10x 杠杆的期货模式下(OKX 隔离保证金),
timeframe 15m,交易 BTC/USDT、ETH/USDT、TRX/USDT。
原策略的止损阈值是按 **1x 杠杆(无杠杆)** 设计的,但实际运行在 10x 杠杆下。
Freqtrade 的 `current_profit``stoploss` 都是**保证金维度**的值,10x 杠杆会把价格
变动放大 10 倍,导致所有止损/保本阈值被压缩到原来的 1/10。
## 二、问题:止损被杠杆压缩到极窄
### Freqtrade 的杠杆计算公式
```
current_profit = (价格变动比例) × leverage ← 保证金维度
stop_loss_price = current_price × (1 - stoploss / leverage) ← 实际止损价
```
### 改前:阈值被压缩 10 倍
| 参数 | 值(保证金维度) | 实际价格含义 | 问题 |
|---|---|---|---|
| `stoploss` | -0.08 | 价格跌 **0.8%** 就止损 | 一根 15m K 线正常波动 0.5~1.5%,一根 K 线就被扫出去 |
| 保本触发 `>0.05` | 保证金+5% | 价格涨 **0.5%** 就保本 | 刚涨一点就锁死,任何回调都被止 |
| 回撤容忍 `return 0.10` | 保证金回撤10% | 容忍价格回撤 **1%** | 正常波动就触发 |
| breakeven `open×1.005` | 入场+0.5% | 保本线在入场+**0.5%** | 几乎等于入场价 |
### 实际后果
```
入场 → 价格涨 0.5% → 保本启动 → 一根 K 线回调 0.3% → 被止损出局 → 错过后面的趋势
```
策略设计是通道突破吃趋势,但止损参数相当于高频炒菜级别,两者严重不匹配。
## 三、改后:阈值 ×10 还原到价格维度
### 逐项对照
| 参数 | 改前 | 改后 | 改前价格含义 | 改后价格含义 |
|---|---|---|---|---|
| `stoploss` | -0.08 | **-0.80** | 价格跌 0.8% 止损 | 价格跌 **8%** 止损 |
| 保本触发 | `>0.05` | **`>0.50`** | 价格涨 0.5% 保本 | 价格涨 **5%** 保本 |
| 第二档 | `>0.15` | **`>1.50`** | 价格涨 1.5% | 价格涨 **15%** |
| 第三档 | `>0.30` | **`>3.00`** | 价格涨 3% | 价格涨 **30%** |
| 回撤容忍 | `return 0.10` | **`return 1.0`** | 容忍回撤 1% | 容忍回撤 **10%** |
| breakeven | `open×1.005` | **`open×1.05`** | 保本在入场+0.5% | 保本在入场+**5%** |
| 兜底 | `return 1.0` | **`return 10.0`** | 止损=$0→被挡→用硬止损 | 同理($0→被挡→用硬止损)|
### 关于 `stoploss` = -0.80
完整 ×10 是 -0.80(保证金-80% = 价格-8%)。10x 杠杆下 OKX 隔离保证金维持保证金率
约 1~2%,价格跌 8~9% 接近强平线。止损设在 -80% 意味着:
- 价格跌 8% 时触发止损,离强平还有约 1% 的缓冲
- 最大限度给趋势空间,不会被任何正常波动扫出去
- **风险**:如果止损滑点或急速下跌,可能被交易所强平而止损单未成交
### 关于兜底 `return 10.0`
`return 10.0` 的计算:`stop_price = current × (1 - 10/10) = $0`。止损设在 $0
比任何现有止损都低,被 Freqtrade 的"止损只升不降"规则挡住,硬止损保留。
这与 1x 下 `return 1.0``1 - 1/1 = 0`,也是 $0)行为完全等价。
## 四、改后代码(trade.leverage 动态联动版)
所有阈值通过 `trade.leverage` 动态计算,当前 10x 时行为与写死值完全一致,
如果未来杠杆变化会自动适配。
```python
# 硬止损(类属性,拿不到 trade.leverage,因 leverage() 固定返回 10.0 故 -0.80 正确)
stoploss = -0.80
def custom_stoploss(self, pair, trade, current_time, current_rate, current_profit, **kwargs):
L = trade.leverage
# 盈利 > 价格+30%: 允许 10% 价格回撤
if current_profit > 0.30 * L:
return 0.10 * L
# 盈利 > 价格+15%: 允许 10% 价格回撤
if current_profit > 0.15 * L:
return 0.10 * L
# 盈利 > 价格+5%: 止损上移到保本+5%
if current_profit > 0.05 * L:
breakeven_target = trade.open_rate * 1.05
return (current_rate - breakeven_target) / current_rate * L
# 兜底:$0→被挡→用硬止损(-80% 保证金 = -8% 价格)
return L
```
### 逐项对照(L=10 时与写死值一致)
| 表达式 | L=10 | 原写死值 | 价格含义 |
|---|---|---|---|
| `0.30 × L` | 3.00 | 3.00 | 价格+30% |
| `0.15 × L` | 1.50 | 1.50 | 价格+15% |
| `0.05 × L` | 0.50 | 0.50 | 价格+5% |
| `0.10 × L` | 1.0 | 1.0 | 允许价格回撤10% |
| `return L` | 10.0 | 10.0 | $0→被挡→用硬止损 |
## 五、Breakeven 返回值 Bug 修复
### Bug 描述
freqtrade 内部对 `custom_stoploss` 返回值的处理公式(`trade_model.py:837`):
```
stop_price = current_rate × (1 - 返回值 / leverage)
```
返回值是**保证金维度**的,freqtrade 内部会再除以 leverage。
原代码的 breakeven 返回值缺少 ×10
```python
# 原代码(有 bug
return (current_rate - breakeven_target) / current_rate
# 返回的是价格维度比例,但 freqtrade 当作保证金维度再除以 10
```
### Bug 影响
以入场 $100,000、当前价 $108,000 为例:
| | 原代码(bug) | 修复后 |
|---|---|---|
| 返回值 | 0.0278 | 0.278 |
| freqtrade 计算 | `108000 × (1 - 0.0278/10)` | `108000 × (1 - 0.278/10)` |
| 实际止损价 | **$107,700**(比预期高 $2,700 | **$105,000** ✓ |
| 效果 | 止损线被杠杆压缩 10 倍,过于贴近当前价 | 止损线正确钉在保本+5% |
修复方式:返回值乘以 `trade.leverage``× L`)。
## 六、改后行为对比(以 BTC $100,000 入场为例)
| 场景 | 改前 | 改后 |
|---|---|---|
| 入场后跌 0.8% | 保证金-8%,**触发硬止损,亏 $800 出局** | 保证金-8%,离 -80% 远,**继续持有** |
| 涨 0.5% 后回调 0.3% | 保本启动,**被止损出局,白干** | 还没到 5% 保本线,**继续持有** |
| 涨 5% 后回调 1% | 早被止损了 | 保本启动(止损在+5%),回调 1% **还在持有** |
| 涨 15% 后回调 10% | 不可能走到这 | 触发第二档止损,**仍盈利 +5% 出局** |
| 涨 30% 后回调 10% | 不可能走到这 | 触发第三档止损,**仍盈利 +20% 出局** |
| 跌 8% | 不可能走到这 | **触发硬止损,亏保证金 80% 出局** |
## 七、风险提示
1. **单次止损亏损极大**:从保证金-8% 变为-80%,每次止损亏掉保证金的 80%,
需要严格控制仓位和并发持仓数
2. **接近强平线**:价格-8% 止损与 OKX 强平线(约-8~9%)非常接近,
急速下跌时止损单可能来不及成交就被强平
3. **建议调低仓位**`max_open_trades``stake_amount` 适当降低,确保单次止损
不至于严重影响总资金
4. **需观察实盘表现**:参数调整后建议密切观察 1~2 周的交易记录,看止损频率是否下降、
盈亏比是否改善
5. **未改 ROI 止盈**`minimal_roi = {"0": 100}` 保持不变(等于关闭 ROI 止盈),
仍然依赖信号出场(跌破 141 周期低点),趋势策略让利润跑是合理的
## 八、部署记录
### 2026-08-21:止损阈值 ×10
- 将所有保证金维度的止损阈值乘以 10,抵消 10x 杠杆压缩
- `stoploss`: -0.08 → -0.30 → -0.80
- 部署方式:scp + systemctl restart freqtrade
- 服务状态:active (running)
### 2026-08-22trade.leverage 动态联动 + breakeven bug 修复
- 所有写死阈值改为通过 `trade.leverage` 动态计算(6 处改动)
- 修复 breakeven 返回值缺少 ×leverage 的 bug(止损线被杠杆压缩 10 倍)
- `stoploss` 类属性保持 -0.80`leverage()` 固定返回 10.0,类属性值正确)
- 部署方式:scp + systemctl restart freqtrade
- 服务状态:active (running)
### 2026-08-22config.json stoploss 覆盖修复
- **问题**:前两次部署只改了策略文件,未改 `config.json`。Freqtrade 中 config 的
`stoploss` 会覆盖策略类的 `stoploss` 属性,导致线上实际硬止损仍是旧的 -0.10
(保证金 -10% = 价格 -1%),修改后的 -0.80 从未生效。
- **后果**trade id=43ETH/USDT8/21 22:00 开仓)最高仅 +1.28% 价格,
未达保本触发线,custom_stoploss 返回兜底值被挡,价格跌 1% 即被旧硬止损扫出,
亏保证金 12.45%(-$13.53)。正是本文第二节描述的"改前"失败模式。
- **修复**`config.json``"stoploss": -0.1``"stoploss": -0.80`
- 部署方式:ssh sed + systemctl restart freqtrade
- 服务状态:active (running),启动日志 RPC 确认 `Stoploss: -0.8`
- **教训**:改策略的 `stoploss` 类属性时,必须同步检查 config.json 是否有 `stoploss`
字段覆盖;两者不一致时 config 优先。后续部署清单应包含此项校验。
- 本地文件:`user_data/strategies/multi_asset_channel_breakout_v5.py`
- 远程路径:`vultr:/opt/freqtrade/user_data/strategies/multi_asset_channel_breakout_v5.py`
- 远程配置:`vultr:/opt/freqtrade/user_data/config.json`