# 顺势加仓（滚仓）详细说明

本文档描述 **顺势加仓 / 滚仓** 的完整业务逻辑、计仓公式、四种加仓方式、程序监控与生命周期规则。实现代码见 `strategy_roll_lib.py`、`strategy_roll_monitor_lib.py`、`strategy_register.py`。

---

## 1. 适用范围与前置条件

| 项目 | 规则 |
|------|------|
| 计仓模式 | **仅「以损定仓」**（`POSITION_SIZING_MODE=risk`）；全仓杠杆模式禁止滚仓 |
| 持仓 | 须先在「实盘下单」存在 **active** 的 `order_monitors`，且交易所有同向持仓 |
| 趋势互斥 | 存在 **active** 趋势回调计划时不可滚仓 |
| 腿数上限 | 做多 / 做空各最多 **3 次**滚仓（仅计 **已成交** 的 `roll_legs`） |
| 同时监控 | **同一滚仓组** 最多 **1 条 pending** 腿；成交或删除/失效后再提交下一腿 |
| 止盈 | 全程使用 **首仓** `order_monitors.take_profit`，滚仓不改止盈 |
| 止损 | 每次提交填写 **新统一止损价 S**；成交后交易所 TP/SL 同步（止盈仍为首仓） |

---

## 2. 风险预算（不可手改）

- 读取所选监控单：`order_monitors.risk_percent`
- 风险预算：**B = 当前交易基数 × risk%**（`get_trading_capital_usdt()` × 监控 risk%）
- 页面规则区展示当前 risk%，表单 **不提供** 风险% 输入框

**方案 C（定稿）**：加仓后若价格打到 **新止损 S**，合并持仓的总亏损 **≤ B**（约等于 1 个风险单位）。浮盈通过 **触发时刻的 mark 价、当时持仓均价与张数** 进入公式，不在提交时固定张数。

---

## 3. 计仓公式

变量：

- `Q1, E1`：触发时现有持仓张数、均价  
- `E2`：加仓成交价（市价腿 ≈ 当时 mark；程序监控腿在 **穿越触发时** 用当时 mark 重算）  
- `S`：提交时填写的统一止损价  
- `B`：风险预算（U）  
- `cs`：合约 `contractSize`（U 本位线性永续）

**做多**（须 `S < E2`）：

```text
(Q1 + Q2) × (avg − S) × cs = B
avg = (Q1·E1 + Q2·E2) / (Q1 + Q2)

=> Q2 = (B/cs − Q1·(E1 − S)) / (E2 − S)
```

**做空**（须 `S > E2`）：

```text
=> Q2 = (B/cs − Q1·(S − E1)) / (S − E2)
```

若 `Q2 ≤ 0`：不加仓 / 监控腿 **失效**，提示「已满足风险上限或无法再加」。

预览与市价执行前用当前 mark 估算；**斐波 / 突破** 在 **触发瞬间** 按当时持仓与 mark **重新计算** 张数后再市价下单。

---

## 4. 四种加仓方式

### 4.1 市价加仓

| 输入 | 仅 **新止损价 S** |
| 执行 | 预览 → **10 秒确认** → 立即市价成交 → 更新止损 |
| 显示 | `市价加仓` |

### 4.2 斐波 0.618 / 0.786

| 输入 | 上沿 H、下沿 L、新止损 S |
| 限价 | 由 H/L 按斐波算 **加仓价 P**（不打交易所限价单） |
| 触发 | 程序监控 **mark**：<br>• **多**：mark **向下穿越** P → 市价加<br>• **空**：mark **向上穿越** P → 市价加 |
| 失效 | **止盈侧**：多 mark≥H；空 mark≤L |
| 显示 | `斐波0.618` / `斐波0.786` |

### 4.3 突破加仓

| 输入 | **突破价 B**、新止损 S |
| 触发 | 程序监控 **mark**：<br>• **多**：mark **向上穿越** B → 市价加<br>• **空**：mark **向下穿越** B → 市价加 |
| 失效 | **止损侧**：多 mark≤S；空 mark≥S（未突破先向止损侧） |
| 显示 | `突破加仓` |

几何校验（做多示例）：

- 斐波：S < P < 当前价（回调加仓）  
- 突破：S < B < 当前价（向上突破再加）

---

## 5. 程序监控技术要点

- **监控价**：统一使用 **标记价 mark**（`get_mark_price` 或 `get_price`）  
- **穿越判定**：比较 `last_mark_price`（上一 tick 存库）与当前 mark，避免重复触发  
  - 例：做多斐波：`prev > P` 且 `mark ≤ P`  
- **轮询**：各所后台任务调用 `check_roll_monitors(cfg)`  
- **成交后**：`replace_tpsl` 更新交易所止损；`order_monitors.stop_loss` 同步为 S  

---

## 6. 生命周期与权限

```text
提交 pending → [监控中] ──穿越触发──→ filled → 可提交下一腿
                 │
                 ├── 用户删除 → cancelled（不可修改，仅删除）
                 ├── 失效规则 → invalidated
                 └── 手动平仓 / 监控结案 → roll_group closed，pending 清除
```

| 规则 | 说明 |
|------|------|
| 提交后不可改 | pending 腿参数不可编辑，只能 **删除** |
| 手动平仓 | 实例页删单/平仓、中控持仓平仓 → 调用 `roll_sync_after_external_close` |
| 历史保留 | **filled** 腿写入库与策略复盘快照；关组后 pending 清除，已成交腿仍可在「策略交易记录」中查看 |

API：

- `POST /strategy/roll/preview` — JSON 预览  
- `POST /strategy/roll/execute` — 提交市价或监控计划  
- `POST /strategy/roll/cancel/<leg_id>` — 删除 pending 腿  
- `POST /api/hub/roll/sync-flat` — 中控平仓后同步（内部）  

---

## 7. 数据表

**roll_groups**（绑定 `order_monitor_id`）

- 首仓 TP/SL、`current_stop_loss`、`leg_count`（**已成交**次数）、`risk_percent` 快照  

**roll_legs**

| 字段 | 说明 |
|------|------|
| add_mode | 市价加仓 / 斐波0.618 / 斐波0.786 / 突破加仓 |
| limit_price | 斐波限价 P |
| breakthrough_price | 突破价 B |
| new_stop_loss | 统一止损 S |
| last_mark_price | 上一 tick mark（穿越检测） |
| status | pending / filled / cancelled / invalidated |

---

## 8. 操作流程（建议）

1. 在「实盘下单」已有同向持仓与监控单  
2. 打开 **策略交易 → 顺势加仓**，选择币种（方向自动锁定）  
3. 选择加仓方式，填写对应价格字段 → **预览**  
4. 市价：等待 10 秒 → **执行滚仓**；斐波/突破：确认后提交监控  
5. 监控中可在「最近滚仓腿」**删除**；成交后再提交下一腿（最多 3 次）  

---

## 9. 相关文件

| 文件 | 职责 |
|------|------|
| `strategy_roll_lib.py` | 计仓、校验、穿越/失效纯函数 |
| `strategy_roll_monitor_lib.py` | 定时监控、触价成交、外部平仓同步 |
| `strategy_register.py` | 预览/执行/删除路由 |
| `static/strategy_roll.js` | 方向锁定、字段显隐、预览与 10 秒确认 |
| `strategy_templates/strategy_roll_panel.html` | 右栏 UI |

---

## 10. 与旧版差异摘要

- 风险% 从监控单读取，不再手填  
- 止损为 **绝对价格**，不再使用「止损偏移%」  
- 斐波/突破改为 **程序盯 mark + 触价市价**，不再挂交易所限价单  
- 新增 **突破加仓**  
- pending **不可改、可删**；手动平仓自动结束滚仓监控  
