refactor: 移除 gate_bot,统一为三所架构并更新文档

删除 crypto_monitor_gate_bot 目录,中控与子代理改为 binance/okx/gate 三账户;
文档与 UI 文案「四所」改为「三所」;新增清库前一次性配置备份脚本。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-04 22:00:08 +08:00
parent be51eee73f
commit 9f67de3677
138 changed files with 26395 additions and 40057 deletions
+130 -130
View File
@@ -1,130 +1,130 @@
# 账户冷静期 / 日冻结风控
所实例(币安 / OKX / Gate / Gate 趋势)共用 `account_risk_lib.py`
**仅用户主动平仓**计入风控;交易所止盈/止损、空仓同步、改保本/改委托等**不触发**冷静期。
## 状态展示
实例页顶、中控监控卡片账户名旁显示风控徽章:
| 状态 | 含义 | 倒计时 |
|------|------|--------|
| 正常 | 可新开仓 | 无 |
| 1h冻结 | 冷静期中(通常为复盘后缩短的 1 小时) | 剩余时间,如 `1h冻结 · 52m 08s` |
| 4h冻结 | 冷静期中(默认 4 小时) | 剩余时间,如 `4h冻结 · 3h 12m` |
| 日冻结 | 当日禁止一切新开仓 | 至下一 **交易日切点**`TRADING_DAY_RESET_HOUR` |
- 倒计时每秒刷新;到期后徽章自动恢复为 **正常**(下次轮询/API 刷新会再次对齐服务端状态)。
- 鼠标悬停徽章可见完整说明(含解除时刻,如有)。
## 什么算「手动平仓」(计入风控)
以下操作通过 `close_source` 登记为 **用户主动平仓**
| 来源标识 | 操作 |
|----------|------|
| `user_instance` | 实例页删单/手动平仓(`del_order` |
| `user_hub` | 中控「平仓」「全平」「紧急全平」 |
| `user_trend_stop` | 趋势计划 **「结束计划」**(手动结束) |
**不算**手动平仓(不触发风控):
- 趋势 **「保本移交下单监控」**
- 中控/实例修改委托、挂止盈止损、移动保本
- 交易所止盈/止损/条件单成交
- 后台 `reconcile_external_closes` 空仓同步(即使记账为「外部平仓」)
- 监控轮询自动止盈/止损/保本
## 触发规则
| 事件 | 行为 |
|------|------|
| 第 1 次用户主动平仓 | 默认 **4h** 冷静期 |
| 第 2 次用户主动平仓(同一交易日) | **日冻结** |
| 复盘勾选任意情绪标签 | **日冻结** |
| 复盘:离场=手动平仓 且说明非空 | 将当前冷静期降为 **1h**(须处于 4h 档冷静期中) |
情绪标签:怕踏空、报复开仓、盈利飘了、拿不住单、扛单、重仓违规。
### 复盘缩短为 1h
任选一种方式,并填写说明:
| 方式 | 必填 |
|------|------|
| **复盘表单**提交 | 离场触发 = **手动平仓**;**离场补充** 非空(不是下方「备注」) |
| **核对修改**保存 | 结果 = **手动平仓****备注** 非空 |
说明:
- 中控全平 / 实例手动平仓后,只要在 4h 窗口内完成上述操作即可降为 1h。
- 复盘保存后会同步更新 `last_close_at_ms`,倒计时以 **最后一次手动平仓 + 当前档位数** 为准,不会继续读库内旧 4h 结束时间。
- 1h 窗口已结束后,即使库里残留旧 `cooloff_until_ms`,状态也会恢复 **正常**
- 若超过「平仓 + 1h」才复盘,则从 **保存复盘时刻** 起再计 1h(不延长原 4h)。
- **止盈 / 保本止盈 / 止损** 等自动平仓不触发风控,也不会刷新冷静期。
- 代码更新后需 **重启对应实例** 并硬刷新页面。
### 倒计时与标签
- 结束时刻 = `last_close_at_ms + cooloff_hours``APP_TIMEZONE` 默认北京时间)
- 1h / 4h 标签按实际剩余时长判断,与倒计时一致
- 切交易日后,若冷静期已过期,自动清库内残留字段
## 环境变量
```env
RISK_CONTROL_ENABLED=true
RISK_COOLING_HOURS_MANUAL=4
RISK_COOLING_HOURS_MANUAL_JOURNAL=1
RISK_MANUAL_CLOSE_DAILY_LIMIT=2
RISK_MOOD_ISSUES_DAILY_FREEZE=true
TRADING_DAY_RESET_HOUR=8
APP_TIMEZONE=Asia/Shanghai
```
`RISK_COOLING_HOURS_EXTERNAL` 已废弃(外部平仓不再触发风控)。
## API 与 `risk_status` 字段
| 接口 | 说明 |
|------|------|
| `GET /api/account_snapshot` | 实例页轮询,含 `risk_status` |
| `GET /api/account_risk_status` | hub_bridge 专用 |
| `GET /api/hub/monitor` | 中控监控板,每账户含 `risk_status` |
| `POST /api/hub/account-risk/user-close` | 中控登记用户平仓,`body: { source, count }` |
`risk_status` 主要字段:
| 字段 | 说明 |
|------|------|
| `status` | `normal` / `freeze_1h` / `freeze_4h` / `freeze_daily` / `freeze_position` |
| `status_label` | 中文标签 |
| `can_trade` | 是否允许新开仓(仅风控维度) |
| `reason` | 悬停提示文案 |
| `active_count` / `max_active_positions` | 当前活跃持仓与 `.env``MAX_ACTIVE_POSITIONS` |
| `cooloff_until_ms` | 1h/4h 冷静期结束时间戳(毫秒) |
| `freeze_until_ms` | 倒计时结束时间戳(日冻结为下一交易日切点) |
| `freeze_remaining_sec` | 服务端计算的剩余秒数(供调试) |
**仓位上限冻结**:当 **计入上限的** 活跃持仓数(不含趋势回调)≥ 实例 `.env``MAX_ACTIVE_POSITIONS`(默认 1)且账户无时间类冻结时,徽章显示 **仓位上限冻结**;此时 **新开仓** 被禁止,但 **顺势加仓**(在已有同向监控持仓上加仓)仍可用。仅存在趋势回调持仓时不触发该冻结。时间冻结(1h/4h/日)优先展示。
`risk_status.can_roll`:仓位上限冻结时为 `true`,表示顺势加仓不受该冻结限制。
## 前端倒计时
- 共用脚本:`static/account_risk_badge.js?v=4`
- 样式:`static/account_risk_badge.css`
- 展示格式:`4h冻结 · 3h 12m`;日冻结为距下一交易日切点剩余时间
- 倒计时优先用服务端 `freeze_remaining_sec` 推算结束时刻,避免绝对时间戳与时区/脏数据偏差
- 服务端在冷静期**已结束**或锚点无效时**自动清库**,避免重启后误读旧 `account_risk_state` 仍显示冻结
- 无效的未来 `last_close_at_ms` **不会**被当作「现在」重启计时
- 若当日手动平仓**已复盘**(journal 有说明)且 1h 窗口已过,即使 risk 表被误写也会强制恢复 **正常**
- 勿与交易记录列表中的历史平仓时间混淆:风控只看 `account_risk_state` 表内 **最后一次用户主动平仓** 及其复盘结果
## 相关代码
- `account_risk_lib.py` — 状态机、`enrich_risk_status_countdown``apply_position_limit_risk``on_user_initiated_close`
- `hub_bridge.py``/api/hub/account-risk/user-close`
- `manual_trading_hub/hub.py` — 中控平仓成功后调用 user-close
- `strategy_trend_register.py``stop_trend_pullback` 结束计划时登记风控
- `tests/test_account_risk_lib.py`
# 账户冷静期 / 日冻结风控
所实例(币安 / OKX / Gate / Gate)共用 `account_risk_lib.py`
**仅用户主动平仓**计入风控;交易所止盈/止损、空仓同步、改保本/改委托等**不触发**冷静期。
## 状态展示
实例页顶、中控监控卡片账户名旁显示风控徽章:
| 状态 | 含义 | 倒计时 |
|------|------|--------|
| 正常 | 可新开仓 | 无 |
| 1h冻结 | 冷静期中(通常为复盘后缩短的 1 小时) | 剩余时间,如 `1h冻结 · 52m 08s` |
| 4h冻结 | 冷静期中(默认 4 小时) | 剩余时间,如 `4h冻结 · 3h 12m` |
| 日冻结 | 当日禁止一切新开仓 | 至下一 **交易日切点**`TRADING_DAY_RESET_HOUR` |
- 倒计时每秒刷新;到期后徽章自动恢复为 **正常**(下次轮询/API 刷新会再次对齐服务端状态)。
- 鼠标悬停徽章可见完整说明(含解除时刻,如有)。
## 什么算「手动平仓」(计入风控)
以下操作通过 `close_source` 登记为 **用户主动平仓**
| 来源标识 | 操作 |
|----------|------|
| `user_instance` | 实例页删单/手动平仓(`del_order` |
| `user_hub` | 中控「平仓」「全平」「紧急全平」 |
| `user_trend_stop` | 趋势计划 **「结束计划」**(手动结束) |
**不算**手动平仓(不触发风控):
- 趋势 **「保本移交下单监控」**
- 中控/实例修改委托、挂止盈止损、移动保本
- 交易所止盈/止损/条件单成交
- 后台 `reconcile_external_closes` 空仓同步(即使记账为「外部平仓」)
- 监控轮询自动止盈/止损/保本
## 触发规则
| 事件 | 行为 |
|------|------|
| 第 1 次用户主动平仓 | 默认 **4h** 冷静期 |
| 第 2 次用户主动平仓(同一交易日) | **日冻结** |
| 复盘勾选任意情绪标签 | **日冻结** |
| 复盘:离场=手动平仓 且说明非空 | 将当前冷静期降为 **1h**(须处于 4h 档冷静期中) |
情绪标签:怕踏空、报复开仓、盈利飘了、拿不住单、扛单、重仓违规。
### 复盘缩短为 1h
任选一种方式,并填写说明:
| 方式 | 必填 |
|------|------|
| **复盘表单**提交 | 离场触发 = **手动平仓**;**离场补充** 非空(不是下方「备注」) |
| **核对修改**保存 | 结果 = **手动平仓****备注** 非空 |
说明:
- 中控全平 / 实例手动平仓后,只要在 4h 窗口内完成上述操作即可降为 1h。
- 复盘保存后会同步更新 `last_close_at_ms`,倒计时以 **最后一次手动平仓 + 当前档位数** 为准,不会继续读库内旧 4h 结束时间。
- 1h 窗口已结束后,即使库里残留旧 `cooloff_until_ms`,状态也会恢复 **正常**
- 若超过「平仓 + 1h」才复盘,则从 **保存复盘时刻** 起再计 1h(不延长原 4h)。
- **止盈 / 保本止盈 / 止损** 等自动平仓不触发风控,也不会刷新冷静期。
- 代码更新后需 **重启对应实例** 并硬刷新页面。
### 倒计时与标签
- 结束时刻 = `last_close_at_ms + cooloff_hours``APP_TIMEZONE` 默认北京时间)
- 1h / 4h 标签按实际剩余时长判断,与倒计时一致
- 切交易日后,若冷静期已过期,自动清库内残留字段
## 环境变量
```env
RISK_CONTROL_ENABLED=true
RISK_COOLING_HOURS_MANUAL=4
RISK_COOLING_HOURS_MANUAL_JOURNAL=1
RISK_MANUAL_CLOSE_DAILY_LIMIT=2
RISK_MOOD_ISSUES_DAILY_FREEZE=true
TRADING_DAY_RESET_HOUR=8
APP_TIMEZONE=Asia/Shanghai
```
`RISK_COOLING_HOURS_EXTERNAL` 已废弃(外部平仓不再触发风控)。
## API 与 `risk_status` 字段
| 接口 | 说明 |
|------|------|
| `GET /api/account_snapshot` | 实例页轮询,含 `risk_status` |
| `GET /api/account_risk_status` | hub_bridge 专用 |
| `GET /api/hub/monitor` | 中控监控板,每账户含 `risk_status` |
| `POST /api/hub/account-risk/user-close` | 中控登记用户平仓,`body: { source, count }` |
`risk_status` 主要字段:
| 字段 | 说明 |
|------|------|
| `status` | `normal` / `freeze_1h` / `freeze_4h` / `freeze_daily` / `freeze_position` |
| `status_label` | 中文标签 |
| `can_trade` | 是否允许新开仓(仅风控维度) |
| `reason` | 悬停提示文案 |
| `active_count` / `max_active_positions` | 当前活跃持仓与 `.env``MAX_ACTIVE_POSITIONS` |
| `cooloff_until_ms` | 1h/4h 冷静期结束时间戳(毫秒) |
| `freeze_until_ms` | 倒计时结束时间戳(日冻结为下一交易日切点) |
| `freeze_remaining_sec` | 服务端计算的剩余秒数(供调试) |
**仓位上限冻结**:当 **计入上限的** 活跃持仓数(不含趋势回调)≥ 实例 `.env``MAX_ACTIVE_POSITIONS`(默认 1)且账户无时间类冻结时,徽章显示 **仓位上限冻结**;此时 **新开仓** 被禁止,但 **顺势加仓**(在已有同向监控持仓上加仓)仍可用。仅存在趋势回调持仓时不触发该冻结。时间冻结(1h/4h/日)优先展示。
`risk_status.can_roll`:仓位上限冻结时为 `true`,表示顺势加仓不受该冻结限制。
## 前端倒计时
- 共用脚本:`static/account_risk_badge.js?v=4`
- 样式:`static/account_risk_badge.css`
- 展示格式:`4h冻结 · 3h 12m`;日冻结为距下一交易日切点剩余时间
- 倒计时优先用服务端 `freeze_remaining_sec` 推算结束时刻,避免绝对时间戳与时区/脏数据偏差
- 服务端在冷静期**已结束**或锚点无效时**自动清库**,避免重启后误读旧 `account_risk_state` 仍显示冻结
- 无效的未来 `last_close_at_ms` **不会**被当作「现在」重启计时
- 若当日手动平仓**已复盘**(journal 有说明)且 1h 窗口已过,即使 risk 表被误写也会强制恢复 **正常**
- 勿与交易记录列表中的历史平仓时间混淆:风控只看 `account_risk_state` 表内 **最后一次用户主动平仓** 及其复盘结果
## 相关代码
- `account_risk_lib.py` — 状态机、`enrich_risk_status_countdown``apply_position_limit_risk``on_user_initiated_close`
- `hub_bridge.py``/api/hub/account-risk/user-close`
- `manual_trading_hub/hub.py` — 中控平仓成功后调用 user-close
- `strategy_trend_register.py``stop_trend_pullback` 结束计划时登记风控
- `tests/test_account_risk_lib.py`