66 lines
4.6 KiB
Markdown
66 lines
4.6 KiB
Markdown
# 止损/止盈的两种实现方式(双通道)
|
||
|
||
当前确实存在**两种**止损(以及止盈)执行方式,互为备份;逻辑如下。
|
||
|
||
---
|
||
|
||
## 一、两种方式分别是什么
|
||
|
||
### 1. 币安条件单(交易所侧,自动执行)
|
||
|
||
- **做法**:开仓或补挂时,在币安挂 **STOP_MARKET**(止损)和 **TAKE_PROFIT_MARKET**(止盈)条件单,触发价为策略算出的 `stop_loss` / `take_profit` 价格。
|
||
- **触发**:价格到达触发价时,**由币安自动撮合**,无需本机程序在线。
|
||
- **代码位置**:`position_manager._ensure_exchange_sltp_orders` → `client.place_trigger_close_position_order(trigger_type="STOP_MARKET" / "TAKE_PROFIT_MARKET", stop_price=...)`。
|
||
- **特点**:服务重启、断网、本机崩溃后,只要仓位和条件单还在,仍能按价止损/止盈。
|
||
|
||
### 2. 系统 WebSocket 监控(本机侧,到价后市价平仓)
|
||
|
||
- **做法**:本机对每个持仓订阅该交易对价格(WebSocket),在 `_check_single_position` 里用**当前价**和**目标止损/止盈**比较(按保证金的亏损/盈利比例),到价则调用 `close_position(symbol, reason='stop_loss'/'take_profit'/...)`,即**市价平仓**。
|
||
- **触发**:程序判定「当前盈亏已到止损或止盈目标」时,**本机主动发市价平仓单**。
|
||
- **代码位置**:`position_manager._monitor_position_price` → `_check_single_position` → 比较 `pnl_percent_margin` 与 `stop_loss_pct_margin` / 止盈目标 → `close_position(...)`。
|
||
- **特点**:可以做**移动止损、分步止盈(TP1 部分平仓)**等复杂逻辑,这些无法用交易所单一张单实现。
|
||
|
||
---
|
||
|
||
## 二、当前整体流程(开仓后)
|
||
|
||
1. 开仓成交后(或补建/修复后)调用 **`_ensure_exchange_sltp_orders`**:
|
||
- 先取消该 symbol 上已有的 STOP_MARKET / TAKE_PROFIT_MARKET / TRAILING_STOP_MARKET;
|
||
- 再按当前 `position_info` 的止损价、止盈价挂**一张止损 + 一张止盈**(交易所条件单)。
|
||
2. 同时对该 symbol 启动 **WebSocket 监控**(`_monitor_position_price`):
|
||
- 每次收到价格,用**保证金盈亏比例**判断是否到止损/到第一止盈/到第二止盈/到移动止损;
|
||
- 到则 **`close_position(..., reason=...)`**(市价平仓)。
|
||
|
||
因此:**同一笔仓位既有交易所条件单,又有本机监控**,两条路都能触发平仓,形成双通道。
|
||
|
||
---
|
||
|
||
## 三、设计意图与分工
|
||
|
||
- **交易所条件单**:保证在**本机不在线**时(重启、断网、崩溃)仍有止损/止盈保护。
|
||
- **本机 WebSocket**:
|
||
- 实现**移动止损、TP1 部分平仓**等(交易所只挂固定止损/止盈,不会自动“移动”或“分步”);
|
||
- 在**挂单失败**时作为兜底(见下)。
|
||
|
||
---
|
||
|
||
## 四、可能的问题与现状
|
||
|
||
| 问题 | 说明 | 当前处理 |
|
||
|------|------|----------|
|
||
| **重复平仓** | 交易所先触发平仓后,本机再判“到价”可能再发平仓。 | `close_position` 会先查币安是否还有仓位;无仓位则不再下单,仅同步 DB,避免重复市价单。 |
|
||
| **挂单失败只剩 WS** | 若 STOP_MARKET 挂单失败(如 -2021、网络错误),则**只有** WebSocket 能止损。 | 代码已写:挂单失败时打日志「将依赖 WebSocket 监控」,并再次检查当前价是否已穿止损,若已穿则立即市价平仓;未穿则仅靠 WS,进程若挂则无交易所保护。 |
|
||
| **价格源不一致** | 交易所条件单多用 **MARK_PRICE**,本机 WS 多用 last/mark。 | 可能有毫秒级差异,一般先触发的一方完成平仓,另一方发现无仓位即不再操作。 |
|
||
| **移动止损仅本机** | 移动止损(盈利到 X% 上移止损)只能由本机逻辑实现。 | **已改**:在移动止损**激活**或**更新**时,会调用 `_ensure_exchange_sltp_orders`,取消原止损/止盈条件单并按新止损价重挂,使移动止损也有交易所保护。 |
|
||
|
||
---
|
||
|
||
## 五、小结
|
||
|
||
- **是,止损(和止盈)有两种**:
|
||
1)**币安条件单**:到价由交易所自动止损/止盈;
|
||
2)**系统 WebSocket 监控**:到价由本机市价平仓。
|
||
- **两者并存**:同一仓位既有交易所单,又有本机监控,互为备份;本机还负责移动止损、TP1 部分平仓等。
|
||
- **主要风险点**:交易所止损/止盈**挂单失败**时,只剩 WebSocket,进程挂了就无交易所保护。
|
||
- **移动止损**:已在「移动止损激活」与「移动止损更新」时同步至交易所(取消原条件单并按新止损价重挂),本机宕机后交易所仍能按最新移动止损价执行。
|