feat: add copy trading safety and leader pool
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
schema: spec-driven
|
||||
created: 2026-05-03
|
||||
@@ -0,0 +1,384 @@
|
||||
## Context
|
||||
|
||||
PolyHermes 当前把跟单流程拆成两层:
|
||||
|
||||
- `copy_trading_leaders` 保存可被跟单的钱包地址,前端入口是 `Leader 管理`。
|
||||
- `copy_trading` 保存真实跟单配置,前端入口是 `跟单配置`。
|
||||
|
||||
这两层之间缺少“候选池/配仓台”。用户如果想用小仓位摊大饼,只能靠脑子或外部笔记维护候选状态,然后手动创建真实跟单配置。这对真钱交易不够安全:观察、试跟、冷却、淘汰没有独立状态,配置也容易沿用过松默认值。
|
||||
|
||||
本设计新增 `Leader 池`,把它定位为 `Leader 管理` 与 `跟单配置` 中间的决策层。它不替代现有 leader 地址库,也不替代真实跟单配置;它负责帮助用户决定“谁进入候选、谁小额试跟、谁冷却或淘汰”。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 新增左侧菜单入口 `跟单交易 -> Leader 池`,路径为 `/leader-pool`。
|
||||
- 支持把已有 leader 加入池子,并维护池子状态。
|
||||
- 支持从 `Leader 管理` 一键加入池子。
|
||||
- 支持从池子创建保守小额跟单配置。
|
||||
- 在页面上展示池子人数、试跟人数、估算最坏暴露、待处理风险。
|
||||
- 复用现有 leader、账户、跟单配置和统计能力,避免重复业务逻辑。
|
||||
- 用显式确认和保守默认值保护真钱交易安全。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不接入 Polymarket leaderboard 自动发现。
|
||||
- 不自动启用大额跟单。
|
||||
- 不自动加仓。
|
||||
- 不做 AI 预测评分。
|
||||
- 不做复杂多账户资金托管。
|
||||
- 不修改真实 PnL 统计口径。统计中仍必须区分真实归零仓位和行情/持仓数据不可用。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 新增独立 `copy_trading_leader_pool` 表
|
||||
|
||||
采用独立表,不把池子字段塞进 `copy_trading_leaders`。
|
||||
|
||||
原因:
|
||||
|
||||
- `copy_trading_leaders` 是地址库,leader 可以存在但不在当前策略池中。
|
||||
- 池子有状态、来源、建议配置、冷却时间、复核时间,这些是策略决策数据,不是 leader 基础资料。
|
||||
- 后续 leaderboard radar、手动观察、亏损诊断都可以写入同一池子表,而不污染 leader 地址库。
|
||||
|
||||
建议迁移:
|
||||
|
||||
```text
|
||||
backend/src/main/resources/db/migration/V41__create_copy_trading_leader_pool.sql
|
||||
```
|
||||
|
||||
建议字段:
|
||||
|
||||
```text
|
||||
id BIGINT AUTO_INCREMENT PRIMARY KEY
|
||||
leader_id BIGINT NOT NULL
|
||||
status VARCHAR(20) NOT NULL
|
||||
source VARCHAR(50) NOT NULL DEFAULT 'MANUAL'
|
||||
source_rank INT NULL
|
||||
score DECIMAL(20, 8) NULL
|
||||
reason TEXT NULL
|
||||
notes TEXT NULL
|
||||
suggested_fixed_amount DECIMAL(20, 8) NOT NULL DEFAULT 1.00000000
|
||||
suggested_max_daily_orders INT NOT NULL DEFAULT 10
|
||||
suggested_max_daily_loss DECIMAL(20, 8) NOT NULL DEFAULT 5.00000000
|
||||
suggested_min_price DECIMAL(20, 8) NULL DEFAULT 0.10000000
|
||||
suggested_max_price DECIMAL(20, 8) NULL DEFAULT 0.80000000
|
||||
suggested_max_position_value DECIMAL(20, 8) NULL DEFAULT 5.00000000
|
||||
last_reviewed_at BIGINT NULL
|
||||
last_promoted_at BIGINT NULL
|
||||
cooldown_until BIGINT NULL
|
||||
locked BOOLEAN NOT NULL DEFAULT FALSE
|
||||
created_at BIGINT NOT NULL
|
||||
updated_at BIGINT NOT NULL
|
||||
```
|
||||
|
||||
约束与索引:
|
||||
|
||||
```text
|
||||
UNIQUE KEY uk_leader_pool_leader_id (leader_id)
|
||||
INDEX idx_leader_pool_status (status)
|
||||
INDEX idx_leader_pool_source (source)
|
||||
FOREIGN KEY (leader_id) REFERENCES copy_trading_leaders(id) ON DELETE CASCADE
|
||||
```
|
||||
|
||||
v1 池子是全局策略池,不按账户拆分。账户只在创建小额试跟配置时选择;同一个 leader 在池子里只出现一次,避免把“候选观察状态”拆成多份互相打架的笔记。若后续需要多账户独立池,再新增 `account_id` 并迁移为 `UNIQUE(account_id, leader_id)`,本次不做。
|
||||
|
||||
### 2. 状态机后端完整、前端 v1 精简
|
||||
|
||||
后端状态枚举预留:
|
||||
|
||||
```text
|
||||
CANDIDATE
|
||||
WATCH
|
||||
PAPER
|
||||
TRIAL
|
||||
ACTIVE
|
||||
COOLDOWN
|
||||
RETIRED
|
||||
```
|
||||
|
||||
前端 v1 展示:
|
||||
|
||||
```text
|
||||
候选
|
||||
观察
|
||||
小额试跟
|
||||
冷却
|
||||
淘汰
|
||||
```
|
||||
|
||||
原因:
|
||||
|
||||
- 后端预留可以让后续 radar 或自动规则不需要迁移状态字段。
|
||||
- 前端不一次暴露太多状态,避免用户每天面对一堆概念。
|
||||
- 锁定是独立布尔字段 `locked`,不是状态。这样 `TRIAL + locked`、`COOLDOWN + locked` 都能表达,不会把“交易阶段”和“自动任务是否可改”混在一起。
|
||||
|
||||
状态更新规则:
|
||||
|
||||
- `RETIRED` 不删除 leader 地址,只让池子项退出关注。
|
||||
- `COOLDOWN` 可以设置 `cooldownUntil`。
|
||||
- `locked=true` 的池子项不允许被后续自动任务改状态。v1 没有自动任务,但字段先保留。
|
||||
|
||||
状态流:
|
||||
|
||||
```text
|
||||
+---------+
|
||||
| RETIRED |
|
||||
+---------+
|
||||
^
|
||||
|
|
||||
CANDIDATE -> WATCH -> TRIAL -> ACTIVE
|
||||
| | |
|
||||
+----------+--------+
|
||||
|
|
||||
v
|
||||
COOLDOWN
|
||||
|
||||
locked=true 是覆盖层,不是状态:
|
||||
任何状态 + locked=true => 后续自动任务不得改状态
|
||||
```
|
||||
|
||||
### 3. 创建试跟配置必须复用 `CopyTradingService.createCopyTrading`
|
||||
|
||||
新增 `LeaderPoolService.createTrialConfig`,内部组装 `CopyTradingCreateRequest`,然后调用现有 `CopyTradingService.createCopyTrading`。
|
||||
|
||||
原因:
|
||||
|
||||
- 现有服务已经处理账户、leader、模板、监听更新、字段校验。
|
||||
- 不复制跟单创建逻辑,避免两套规则不同步。
|
||||
|
||||
默认请求建议:
|
||||
|
||||
```text
|
||||
enableImmediately = false
|
||||
confirm = false
|
||||
enabled = false
|
||||
copyMode = FIXED
|
||||
fixedAmount = suggestedFixedAmount 默认 1
|
||||
maxOrderSize = suggestedFixedAmount 默认 1
|
||||
minOrderSize = 1
|
||||
maxDailyOrders = suggestedMaxDailyOrders 默认 10
|
||||
maxDailyLoss = suggestedMaxDailyLoss 默认 5
|
||||
priceTolerance = 1
|
||||
minPrice = 0.10
|
||||
maxPrice = 0.80
|
||||
maxPositionValue = 5
|
||||
supportSell = true
|
||||
pushFailedOrders = true
|
||||
pushFilteredOrders = true
|
||||
configName = "Leader池-<leaderName或地址后6位>"
|
||||
```
|
||||
|
||||
`enabled=false` 是推荐默认。若前端允许立即启用,必须弹出确认,并明确展示固定金额、最大日单数、最大日亏损和最大持仓。
|
||||
|
||||
后端也必须执行同一条安全规则:当 `enableImmediately=true` 时,`confirm` 必须为 `true`,否则拒绝创建。真钱交易不能只靠前端弹窗保护。
|
||||
|
||||
创建前还必须检查同一 `accountId + leaderId` 是否已经存在跟单配置。默认拒绝重复创建,并返回已有配置提示。PolyHermes 允许同一 leader 多个跟单配置,但 Leader 池的一键试跟不应该制造重复配置;真要高级配置,用户应该走 `跟单配置` 页面手动创建。
|
||||
|
||||
建议配置必须在后端校验,不只靠前端输入框:
|
||||
|
||||
```text
|
||||
suggestedFixedAmount > 0
|
||||
suggestedMaxDailyOrders between 1 and 100
|
||||
suggestedMaxDailyLoss > 0
|
||||
suggestedMinPrice / suggestedMaxPrice in [0, 1] when present
|
||||
suggestedMinPrice <= suggestedMaxPrice when both present
|
||||
suggestedMaxPositionValue > 0 when present
|
||||
```
|
||||
|
||||
这是“雨露均沾”的安全边界:小额可以分散,但不能因为一个坏输入把单个 leader 变成隐形重仓。
|
||||
|
||||
### 4. 新增 leader 池 API,路径归在 copy-trading 下
|
||||
|
||||
新增控制器:
|
||||
|
||||
```text
|
||||
backend/src/main/kotlin/com/wrbug/polymarketbot/controller/copytrading/leaderpool/LeaderPoolController.kt
|
||||
```
|
||||
|
||||
API:
|
||||
|
||||
```text
|
||||
POST /api/copy-trading/leader-pool/list
|
||||
POST /api/copy-trading/leader-pool/add
|
||||
POST /api/copy-trading/leader-pool/update-status
|
||||
POST /api/copy-trading/leader-pool/update-plan
|
||||
POST /api/copy-trading/leader-pool/create-trial-config
|
||||
POST /api/copy-trading/leader-pool/remove
|
||||
```
|
||||
|
||||
`list` 响应应聚合:
|
||||
|
||||
- leader 基础信息。
|
||||
- 池子状态和建议配置。
|
||||
- 该 leader 的跟单配置数量。
|
||||
- 该 leader 是否已有启用中的跟单配置。
|
||||
- 估算最坏暴露字段。
|
||||
|
||||
聚合必须使用批量查询或聚合查询,不能对每个池子项逐个查 leader 和跟单配置。计划新增 repository 方法,例如:
|
||||
|
||||
```text
|
||||
LeaderRepository.findAllById(...)
|
||||
CopyTradingRepository.findByLeaderIdIn(...)
|
||||
CopyTradingRepository.countByLeaderIdInGrouped(...) 或用 findByLeaderIdIn 后内存分组
|
||||
```
|
||||
|
||||
这保持 v1 足够简单,同时避免池子 50 人时打出 100 多次 SQL。软件会在你最懒得排查的时候提醒你什么叫 N+1。
|
||||
|
||||
主要数据流:
|
||||
|
||||
```text
|
||||
Leader 管理
|
||||
-> POST /leader-pool/add
|
||||
-> LeaderPoolService.addToPool
|
||||
-> copy_trading_leader_pool
|
||||
|
||||
Leader 池页面
|
||||
-> POST /leader-pool/list
|
||||
-> LeaderPoolService.getPoolList
|
||||
-> batch read leaders + copy_trading
|
||||
-> summary cards + table
|
||||
|
||||
Leader 池创建小额试跟
|
||||
-> POST /leader-pool/create-trial-config
|
||||
-> LeaderPoolService.createTrialConfig
|
||||
-> CopyTradingService.createCopyTrading
|
||||
-> copy_trading
|
||||
-> pool.status = TRIAL only after success
|
||||
```
|
||||
|
||||
### 5. 前端页面独立,Leader 管理只放轻入口
|
||||
|
||||
新增页面:
|
||||
|
||||
```text
|
||||
frontend/src/pages/LeaderPool.tsx
|
||||
```
|
||||
|
||||
修改路由:
|
||||
|
||||
```text
|
||||
frontend/src/App.tsx
|
||||
```
|
||||
|
||||
修改菜单:
|
||||
|
||||
```text
|
||||
frontend/src/components/Layout.tsx
|
||||
```
|
||||
|
||||
菜单位置:
|
||||
|
||||
```text
|
||||
跟单交易
|
||||
跟单配置
|
||||
Leader 池
|
||||
Leader 管理
|
||||
跟单模板
|
||||
回测
|
||||
```
|
||||
|
||||
`LeaderList.tsx` 只新增“加入 Leader 池”操作。不要把池子状态和预算管理塞进 Leader 管理页。
|
||||
|
||||
`LeaderPool.tsx` 不默认逐行查询 leader 余额。Leader 管理页当前有逐个加载余额的重型交互,但池子页的核心任务是筛选、配仓和创建小额试跟配置;默认列表只展示后端一次返回的聚合字段,profile 和详情可以按需打开。
|
||||
|
||||
### 6. 预算概览只做提示,不做资金托管
|
||||
|
||||
页面顶部显示:
|
||||
|
||||
```text
|
||||
池子人数
|
||||
试跟中人数
|
||||
估算最坏暴露
|
||||
待处理风险
|
||||
```
|
||||
|
||||
估算方式:
|
||||
|
||||
```text
|
||||
TRIAL/ACTIVE 状态的池子项数量 * suggestedMaxPositionValue
|
||||
```
|
||||
|
||||
如果某个池子项没有 `suggestedMaxPositionValue`,使用默认 5。
|
||||
|
||||
v1 可以先不持久化“总试验预算”。页面可用默认 50 显示提示,或提供前端输入但不存库。若实现持久化预算,优先使用现有系统配置能力,不新增复杂账户资金模型。
|
||||
|
||||
### 7. 错误态与空态
|
||||
|
||||
前端必须覆盖:
|
||||
|
||||
- 池子为空:提示从 `Leader 管理` 加入 leader,或在池子页选择已有 leader 加入。
|
||||
- leader 已在池子:加入动作返回明确提示,不创建重复项。
|
||||
- leader 不存在:提示先添加 leader。
|
||||
- 没有账户:创建试跟配置前提示先添加账户。
|
||||
- 创建配置失败:展示后端错误,不更新池子状态。
|
||||
- 创建配置成功:池子状态更新为 `TRIAL`,并给出跳转到 `跟单配置` 的入口。
|
||||
|
||||
### 8. 调度与自动化
|
||||
|
||||
本次不新增定时任务。
|
||||
|
||||
后续 leaderboard radar 可以把候选写入 `copy_trading_leader_pool`,但必须遵守:
|
||||
|
||||
- 不自动创建真实跟单配置。
|
||||
- 不改 `locked=true` 的池子项。
|
||||
- 不自动把 `COOLDOWN` 或 `RETIRED` 改回试跟。
|
||||
|
||||
### 9. 可观测性
|
||||
|
||||
后端日志至少记录:
|
||||
|
||||
- leader 加入池子。
|
||||
- 池子状态变化。
|
||||
- 创建试跟配置成功/失败。
|
||||
- 被拒绝的危险操作,例如重复加入、leader 不存在、账户不存在。
|
||||
|
||||
未来如果接入审计表,可把这些操作迁入审计事件。本次不强制新增审计表。
|
||||
|
||||
### 10. 错误码与国际化
|
||||
|
||||
Leader 池需要独立错误码,不要全部塞进 `BUSINESS_ERROR`。建议在现有错误码体系中新增:
|
||||
|
||||
```text
|
||||
LEADER_POOL_NOT_FOUND(4251)
|
||||
LEADER_POOL_ALREADY_EXISTS(4252)
|
||||
LEADER_POOL_DUPLICATE_TRIAL_CONFIG(4253)
|
||||
LEADER_POOL_CONFIRM_REQUIRED(4254)
|
||||
SERVER_LEADER_POOL_LIST_FAILED(5451)
|
||||
SERVER_LEADER_POOL_UPDATE_FAILED(5452)
|
||||
SERVER_LEADER_POOL_CREATE_TRIAL_FAILED(5453)
|
||||
```
|
||||
|
||||
这些编号避开当前 `ErrorCode` 中已经存在的 `4601` 冲突。实现时必须确认没有新增重复 code。
|
||||
|
||||
同时补齐 `messages_zh_CN.properties`、`messages_zh_TW.properties`、`messages_en.properties`。前端需要能看到明确错误,而不是一个泛泛的“业务逻辑错误”。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Risk] 用户误以为加入池子等于已经跟单 → Mitigation:页面文案明确区分 `观察`、`小额试跟` 和真实 `跟单配置`,创建配置后给出配置状态。
|
||||
- [Risk] 一键创建配置触发真钱交易 → Mitigation:默认 `enabled=false`;若支持立即启用,必须二次确认。
|
||||
- [Risk] 双击或多标签重复创建试跟配置 → Mitigation:前端提交时进入 loading 并禁用按钮;后端按 `accountId + leaderId` 检查已有配置,默认拒绝重复创建。
|
||||
- [Risk] 池子状态和跟单配置状态不一致 → Mitigation:list 响应聚合当前跟单配置数量和启用状态;不把池子状态当作真实交易状态。
|
||||
- [Risk] 同一 leader 重复加入池子 → Mitigation:数据库唯一约束 `leader_id`,服务层返回幂等提示。
|
||||
- [Risk] 并发加入同一 leader 时先查再写仍然冲突 → Mitigation:保留数据库唯一约束,并捕获唯一约束异常,返回“已在池子中”的明确结果。
|
||||
- [Risk] 建议配置输入为负数、超大值或无效价格区间 → Mitigation:后端校验所有建议配置字段,拒绝危险配置,不只依赖前端表单。
|
||||
- [Risk] 池子列表照搬 Leader 管理逐行余额查询导致页面变慢 → Mitigation:池子列表默认只用后端聚合字段,不逐行拉余额。
|
||||
- [Risk] 页面诱导追涨 → Mitigation:v1 不做收益率排行榜主导,不做 AI 评分;重点展示状态、预算、风险和保守配置。
|
||||
- [Risk] 预算只是估算,不等于真实账户风险 → Mitigation:页面文案使用“估算最坏暴露”,不展示为账户余额或保证金。
|
||||
- [Risk] 后续自动 radar 覆盖人工判断 → Mitigation:预留 `locked` 字段,自动任务不得修改锁定项,不得复活冷却/淘汰项。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 新增 Flyway 迁移 `V41__create_copy_trading_leader_pool.sql`。
|
||||
2. 部署后 Flyway 自动创建新表,不改动现有表数据。
|
||||
3. 新增 API 和前端入口上线后,池子默认为空。
|
||||
4. 用户可以从现有 `Leader 管理` 手动加入 leader。
|
||||
5. 回滚时可隐藏前端菜单和 API;新表保留不会影响现有跟单流程。
|
||||
6. 若必须数据库回滚,可删除 `copy_trading_leader_pool` 表;不会影响 `copy_trading_leaders` 和 `copy_trading`。
|
||||
|
||||
## Locked v1 Decisions
|
||||
|
||||
- v1 不持久化“总试验预算”。页面只展示默认 50 的试验预算提示和估算最坏暴露,不新增账户资金模型。
|
||||
- v1 UI 不提供“创建后立即启用”开关。池子创建的小额试跟配置默认 `enabled=false`;`enableImmediately` 与 `confirm` 只作为后端防御和后续扩展预留。
|
||||
- v1 UI 只暴露“候选、观察、小额试跟、冷却、淘汰”。`PAPER` 和 `ACTIVE` 保留在后端枚举中,第一版不进入筛选标签和主操作流。
|
||||
@@ -0,0 +1,35 @@
|
||||
## Why
|
||||
|
||||
PolyHermes 现在有 `Leader 管理` 和 `跟单配置`,但缺少中间的决策层:用户只能先保存 leader,再直接创建真实跟单配置。对于“小仓位、雨露均沾”的摊大饼策略,这会把“观察候选”和“真钱下单”混在一起,容易因为手动判断和配置过松扩大亏损。
|
||||
|
||||
这次变更要新增一个 `Leader 池` 入口,让用户先管理候选、观察、小额试跟、冷却和淘汰,再明确决定是否创建保守的小额跟单配置。
|
||||
|
||||
## What Changes
|
||||
|
||||
- 新增 `Leader 池` 页面入口,放在左侧 `跟单交易` 分组下,位于 `跟单配置` 与 `Leader 管理` 之间。
|
||||
- 新增 leader 池能力,支持把已有 leader 加入池子,并维护候选、观察、小额试跟、冷却、淘汰等状态。
|
||||
- 新增池子预算与风险概览,帮助用户看到试跟人数、建议最坏暴露、待处理风险等组合级信息。
|
||||
- 新增从池子创建保守小额跟单配置的动作,默认使用固定金额、小日单数、小日亏损、价格区间和单 leader 持仓上限。
|
||||
- 在 `Leader 管理` 中增加“加入 Leader 池”的辅助入口,避免用户来回复制地址。
|
||||
- 保留现有 `Leader 管理`、`跟单配置`、统计页和风险安全带,不替换现有工作流。
|
||||
- 不做自动加仓、不做自动启用大额跟单、不做 AI 预测评分。
|
||||
- 不在 v1 自动抓取 Polymarket leaderboard。leaderboard 自动发现后续可接入池子,但不属于本次实现。
|
||||
|
||||
## Capabilities
|
||||
|
||||
### New Capabilities
|
||||
|
||||
- `leader-pool`: 管理用于小仓位摊大饼策略的 leader 候选池,包括状态流转、保守试跟配置创建、组合预算提示和与现有 leader/跟单配置的联动。
|
||||
|
||||
### Modified Capabilities
|
||||
|
||||
无。
|
||||
|
||||
## Impact
|
||||
|
||||
- 后端新增 leader 池实体、迁移、仓库、DTO、服务和控制器。
|
||||
- 后端复用现有 `LeaderService`、`CopyTradingService`、`CopyTradingRepository`,避免重复实现 leader 校验和跟单配置创建逻辑。
|
||||
- 前端新增 `LeaderPool` 页面、路由、菜单项、API service、类型定义和中英文菜单文案。
|
||||
- 前端 `LeaderList` 增加“加入 Leader 池”操作。
|
||||
- 数据库新增 `copy_trading_leader_pool` 表,不修改现有 leader 和跟单配置表的语义。
|
||||
- 交易安全影响:本功能可能创建真实跟单配置,因此必须使用保守默认值、显式确认和非自动加仓策略。
|
||||
@@ -0,0 +1,167 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: 提供 Leader 池入口
|
||||
系统 SHALL 在受保护的 Web 应用中提供 `Leader 池` 页面入口,用于管理小仓位摊大饼策略的 leader 候选池。
|
||||
|
||||
#### Scenario: 左侧菜单展示 Leader 池
|
||||
- **WHEN** 已登录用户打开任意受保护页面
|
||||
- **THEN** 左侧 `跟单交易` 菜单中 MUST 展示 `Leader 池`,并位于 `跟单配置` 与 `Leader 管理` 之间
|
||||
|
||||
#### Scenario: 打开 Leader 池页面
|
||||
- **WHEN** 用户点击左侧菜单中的 `Leader 池`
|
||||
- **THEN** 系统 MUST 导航到 `/leader-pool` 并展示 Leader 池页面
|
||||
|
||||
### Requirement: 管理池子成员
|
||||
系统 SHALL 支持把已有 leader 加入 Leader 池,并保证同一个 leader 在池子中最多只有一个池子项。
|
||||
|
||||
#### Scenario: 从 Leader 管理加入池子
|
||||
- **WHEN** 用户在 `Leader 管理` 页面点击某个 leader 的 `加入 Leader 池`
|
||||
- **THEN** 系统 MUST 为该 leader 创建池子项,并默认状态为 `CANDIDATE`
|
||||
|
||||
#### Scenario: 重复加入同一 leader
|
||||
- **WHEN** 用户尝试把已经在池子中的 leader 再次加入池子
|
||||
- **THEN** 系统 MUST 不创建重复池子项,并 MUST 返回明确提示
|
||||
|
||||
#### Scenario: 并发重复加入同一 leader
|
||||
- **WHEN** 两个请求同时把同一个 leader 加入池子
|
||||
- **THEN** 系统 MUST 最多创建一个池子项,并 MUST 对冲突请求返回已在池子中的明确提示
|
||||
|
||||
#### Scenario: 加入不存在的 leader
|
||||
- **WHEN** 用户请求把不存在的 leader 加入池子
|
||||
- **THEN** 系统 MUST 拒绝请求,并 MUST 返回 leader 不存在的错误
|
||||
|
||||
### Requirement: 维护池子状态
|
||||
系统 SHALL 支持维护 leader 池状态,用于区分候选、观察、小额试跟、冷却和淘汰。
|
||||
|
||||
#### Scenario: 更新池子状态
|
||||
- **WHEN** 用户把某个池子项从 `CANDIDATE` 更新为 `WATCH`、`TRIAL`、`COOLDOWN` 或 `RETIRED`
|
||||
- **THEN** 系统 MUST 保存新状态并更新该池子项的更新时间
|
||||
|
||||
#### Scenario: 冷却状态包含冷却截止时间
|
||||
- **WHEN** 用户把某个池子项设置为 `COOLDOWN` 并提供冷却截止时间
|
||||
- **THEN** 系统 MUST 保存 `cooldownUntil`
|
||||
|
||||
#### Scenario: 淘汰不删除 leader 地址
|
||||
- **WHEN** 用户把某个池子项设置为 `RETIRED`
|
||||
- **THEN** 系统 MUST 保留对应 `copy_trading_leaders` 记录,不得删除 leader 地址
|
||||
|
||||
### Requirement: 展示池子概览
|
||||
系统 SHALL 在 Leader 池页面展示组合级概览,帮助用户理解小仓位策略的风险暴露。
|
||||
|
||||
#### Scenario: 展示统计卡片
|
||||
- **WHEN** 用户打开 Leader 池页面
|
||||
- **THEN** 页面 MUST 展示池子人数、试跟中人数、估算最坏暴露和待处理风险
|
||||
|
||||
#### Scenario: 估算最坏暴露
|
||||
- **WHEN** 池子中存在 `TRIAL` 或 `ACTIVE` 状态项
|
||||
- **THEN** 系统 MUST 使用这些项的建议最大持仓值合计估算最坏暴露
|
||||
|
||||
#### Scenario: 池子为空
|
||||
- **WHEN** 池子没有任何成员
|
||||
- **THEN** 页面 MUST 展示空态,并 MUST 提示用户可以从 `Leader 管理` 加入 leader
|
||||
|
||||
### Requirement: 展示池子列表信息
|
||||
系统 SHALL 在 Leader 池列表中展示池子状态、leader 基础信息、建议配置和现有跟单配置状态。
|
||||
|
||||
#### Scenario: 列表展示 leader 和状态
|
||||
- **WHEN** 用户打开 Leader 池页面且池子中存在成员
|
||||
- **THEN** 列表 MUST 展示 leader 名称或地址、池子状态、来源、建议固定金额、建议每日最大单数、建议每日最大亏损和最后复核时间
|
||||
|
||||
#### Scenario: 展示现有跟单配置状态
|
||||
- **WHEN** 某个池子 leader 已经存在跟单配置
|
||||
- **THEN** 列表 MUST 展示该 leader 的跟单配置数量,并 MUST 标明是否存在启用中的跟单配置
|
||||
|
||||
#### Scenario: 打开外部 profile
|
||||
- **WHEN** 用户点击池子项中的 Polymarket profile 操作
|
||||
- **THEN** 系统 MUST 打开该 leader 对应的 Polymarket profile 地址
|
||||
|
||||
#### Scenario: 池子列表不默认逐行查询余额
|
||||
- **WHEN** 用户打开 Leader 池页面且池子中存在多个成员
|
||||
- **THEN** 页面 MUST NOT 为每个池子项默认逐行请求 leader 余额接口
|
||||
|
||||
### Requirement: 创建保守小额试跟配置
|
||||
系统 SHALL 支持从 Leader 池为某个 leader 创建保守的小额跟单配置,并复用现有跟单配置创建逻辑。
|
||||
|
||||
#### Scenario: 创建默认禁用的试跟配置
|
||||
- **WHEN** 用户从池子项点击创建小额试跟配置并完成确认
|
||||
- **THEN** 系统 MUST 创建 `FIXED` 模式跟单配置,默认固定金额为 1,默认启用状态为禁用
|
||||
|
||||
#### Scenario: 使用保守风控默认值
|
||||
- **WHEN** 系统从池子创建小额试跟配置
|
||||
- **THEN** 创建请求 MUST 使用保守默认值,包括每日最大单数 10、每日最大亏损 5、价格容忍度 1、最低价格 0.10、最高价格 0.80、最大持仓 5
|
||||
|
||||
#### Scenario: 创建成功后更新池子状态
|
||||
- **WHEN** 小额试跟配置创建成功
|
||||
- **THEN** 系统 MUST 把池子项状态更新为 `TRIAL`,并 MUST 记录最后晋升时间
|
||||
|
||||
#### Scenario: 创建失败不更新状态
|
||||
- **WHEN** 小额试跟配置创建失败
|
||||
- **THEN** 系统 MUST 保留原池子状态,并 MUST 向用户展示失败原因
|
||||
|
||||
### Requirement: 保护真钱交易安全
|
||||
系统 SHALL 防止 Leader 池功能在没有明确用户动作的情况下扩大真实交易风险。
|
||||
|
||||
#### Scenario: 不自动创建跟单配置
|
||||
- **WHEN** 用户仅把 leader 加入池子或更新池子状态
|
||||
- **THEN** 系统 MUST NOT 自动创建真实跟单配置
|
||||
|
||||
#### Scenario: 不自动启用大额跟单
|
||||
- **WHEN** 系统从池子创建小额试跟配置
|
||||
- **THEN** 系统 MUST NOT 自动创建大额配置,并 MUST 使用保守小额参数
|
||||
|
||||
#### Scenario: 立即启用需要确认
|
||||
- **WHEN** UI 提供创建后立即启用选项
|
||||
- **THEN** UI MUST 在提交前展示固定金额、每日最大单数、每日最大亏损和最大持仓,并 MUST 要求用户确认
|
||||
|
||||
#### Scenario: 后端拒绝未确认的立即启用
|
||||
- **WHEN** 创建试跟配置请求要求立即启用但没有提供确认标记
|
||||
- **THEN** 后端 MUST 拒绝请求,并 MUST NOT 创建跟单配置
|
||||
|
||||
### Requirement: 支持更新建议配置
|
||||
系统 SHALL 支持用户更新池子项的建议固定金额和建议风控参数,但不得直接修改已有真实跟单配置。
|
||||
|
||||
#### Scenario: 更新建议配置
|
||||
- **WHEN** 用户更新池子项的建议固定金额、每日最大单数、每日最大亏损、价格区间或最大持仓
|
||||
- **THEN** 系统 MUST 保存这些建议字段,并 MUST 更新池子项的更新时间
|
||||
|
||||
#### Scenario: 建议配置不影响已有跟单
|
||||
- **WHEN** 用户只更新池子项建议配置
|
||||
- **THEN** 系统 MUST NOT 修改任何已有 `copy_trading` 记录
|
||||
|
||||
#### Scenario: 拒绝无效建议配置
|
||||
- **WHEN** 用户提交负数固定金额、无效每日最大单数、负数每日亏损、无效价格区间或负数最大持仓
|
||||
- **THEN** 系统 MUST 拒绝保存,并 MUST 保留原建议配置不变
|
||||
|
||||
### Requirement: 提供后端 API
|
||||
系统 SHALL 提供 Leader 池后端 API,用于列表查询、加入池子、状态更新、建议配置更新、创建试跟配置和移除池子项。
|
||||
|
||||
#### Scenario: 查询池子列表
|
||||
- **WHEN** 前端请求 `/api/copy-trading/leader-pool/list`
|
||||
- **THEN** 后端 MUST 返回池子项列表、汇总信息和每个池子项的 leader/跟单配置聚合信息
|
||||
|
||||
#### Scenario: 池子列表使用批量聚合
|
||||
- **WHEN** 后端生成池子列表响应
|
||||
- **THEN** 后端 MUST 使用批量查询或聚合查询获取 leader 与跟单配置信息,不得对每个池子项逐条查询 leader 和跟单配置
|
||||
|
||||
#### Scenario: 创建试跟配置 API
|
||||
- **WHEN** 前端请求 `/api/copy-trading/leader-pool/create-trial-config`
|
||||
- **THEN** 后端 MUST 校验池子项、账户和 leader,并 MUST 通过现有跟单配置服务创建配置
|
||||
|
||||
#### Scenario: 已存在同账户同 leader 跟单配置
|
||||
- **WHEN** 用户为某个账户和 leader 创建试跟配置且该账户已存在该 leader 的跟单配置
|
||||
- **THEN** 系统 MUST 拒绝默认试跟创建,并 MUST 返回已有配置提示
|
||||
|
||||
#### Scenario: 移除池子项
|
||||
- **WHEN** 用户请求移除某个池子项
|
||||
- **THEN** 系统 MUST 只移除池子项,不得删除 leader 地址,不得删除已有跟单配置
|
||||
|
||||
### Requirement: 记录关键操作日志
|
||||
系统 SHALL 对 Leader 池关键操作记录后端日志,便于排查交易相关行为。
|
||||
|
||||
#### Scenario: 记录加入和状态变化
|
||||
- **WHEN** leader 被加入池子或池子状态发生变化
|
||||
- **THEN** 后端 MUST 记录包含 leaderId、池子项 ID 和目标状态的日志
|
||||
|
||||
#### Scenario: 记录试跟配置创建结果
|
||||
- **WHEN** 系统尝试从池子创建小额试跟配置
|
||||
- **THEN** 后端 MUST 记录创建成功或失败日志,并包含 leaderId、accountId 和错误原因
|
||||
@@ -0,0 +1,95 @@
|
||||
## 1. 后端数据模型
|
||||
|
||||
- [x] 1.1 新增 Flyway 迁移 `V41__create_copy_trading_leader_pool.sql`,创建 `copy_trading_leader_pool` 表、`leader_id` 唯一约束、状态/来源索引和 leader 外键。
|
||||
- [x] 1.2 新增 `LeaderPool` JPA 实体,字段覆盖状态、来源、建议配置、复核时间、晋升时间、冷却时间、锁定标记和时间戳。
|
||||
- [x] 1.3 新增 `LeaderPoolRepository`,支持按 leaderId 查询、判断是否存在、按状态查询、按创建时间排序和删除池子项。
|
||||
- [x] 1.4 新增池子状态常量或枚举,覆盖 `CANDIDATE`、`WATCH`、`PAPER`、`TRIAL`、`ACTIVE`、`COOLDOWN`、`RETIRED`;锁定使用独立 `locked` 布尔字段,不作为状态。
|
||||
- [x] 1.5 扩展 `CopyTradingRepository` 或新增查询方法,支持按 leaderId 批量查询/聚合跟单配置,避免 Leader 池列表 N+1 查询。
|
||||
|
||||
## 2. 后端 DTO 与服务
|
||||
|
||||
- [x] 2.1 新增 Leader 池请求/响应 DTO,包括列表请求、加入请求、状态更新请求、建议配置更新请求、创建试跟配置请求和移除请求。
|
||||
- [x] 2.2 为创建试跟配置请求增加 `enableImmediately` 与 `confirm` 字段;当 `enableImmediately=true` 且未确认时后端必须拒绝创建。
|
||||
- [x] 2.3 新增 `LeaderPoolService.addToPool`,校验 leader 存在、处理重复加入,并默认创建 `CANDIDATE` 状态池子项。
|
||||
- [x] 2.4 在 `addToPool` 中捕获数据库唯一约束冲突,并返回“已在池子中”的明确业务结果,覆盖并发重复加入。
|
||||
- [x] 2.5 新增 `LeaderPoolService.getPoolList`,使用批量查询聚合 leader 信息、池子状态、建议配置、跟单配置数量、是否存在启用跟单和汇总概览。
|
||||
- [x] 2.6 新增 `LeaderPoolService.updateStatus`,支持状态更新、冷却截止时间保存、更新时间刷新,并确保淘汰不删除 leader 地址。
|
||||
- [x] 2.7 新增 `LeaderPoolService.updatePlan`,只更新建议固定金额、每日最大单数、每日最大亏损、价格区间和最大持仓,不修改已有 `copy_trading`。
|
||||
- [x] 2.8 新增 `LeaderPoolService.createTrialConfig`,先检查同一 `accountId + leaderId` 是否已有跟单配置,默认拒绝重复创建。
|
||||
- [x] 2.9 `createTrialConfig` 复用 `CopyTradingService.createCopyTrading` 创建默认禁用的保守 `FIXED` 小额跟单配置。
|
||||
- [x] 2.10 创建试跟配置成功后更新池子项为 `TRIAL` 并记录 `lastPromotedAt`;失败时保持原状态并返回错误。
|
||||
- [x] 2.11 在 Leader 池服务中记录加入池子、状态变化、建议配置更新、试跟配置创建成功/失败的关键日志。
|
||||
- [x] 2.12 在 `updatePlan` 和 `createTrialConfig` 中校验建议配置安全边界:固定金额大于 0、每日最大单数 1-100、每日最大亏损大于 0、价格区间在 0-1 且最小价不大于最大价、最大持仓大于 0。
|
||||
- [x] 2.13 新增 Leader 池专用错误码和中英繁三套 i18n 文案,使用不冲突编号 `4251-4254` 与 `5451-5453`,覆盖池子不存在、已存在、重复试跟、立即启用未确认和服务失败。
|
||||
|
||||
## 3. 后端 API
|
||||
|
||||
- [x] 3.1 新增 `LeaderPoolController`,路径为 `/api/copy-trading/leader-pool`。
|
||||
- [x] 3.2 实现 `POST /list`,返回池子列表和汇总概览。
|
||||
- [x] 3.3 实现 `POST /add`,支持从已有 leader 加入池子。
|
||||
- [x] 3.4 实现 `POST /update-status`,支持候选、观察、小额试跟、冷却、淘汰等状态更新。
|
||||
- [x] 3.5 实现 `POST /update-plan`,支持更新建议配置字段。
|
||||
- [x] 3.6 实现 `POST /create-trial-config`,支持创建保守小额试跟配置。
|
||||
- [x] 3.7 实现 `POST /remove`,只移除池子项,不删除 leader 地址,不删除已有跟单配置。
|
||||
- [x] 3.8 为重复加入、并发唯一约束冲突、leader 不存在、账户不存在、池子项不存在、立即启用未确认、重复试跟配置、创建配置失败等错误返回明确业务错误。
|
||||
|
||||
## 4. 前端 API 与类型
|
||||
|
||||
- [x] 4.1 在 `frontend/src/types/index.ts` 新增 Leader 池状态、池子项、汇总、请求和响应类型。
|
||||
- [x] 4.2 在 `frontend/src/services/api.ts` 新增 `leaderPool` API 分组,覆盖 list、add、updateStatus、updatePlan、createTrialConfig、remove。
|
||||
- [x] 4.3 确保前端类型包含跟单配置数量、是否有启用跟单、建议最大持仓和估算暴露字段。
|
||||
|
||||
## 5. 前端入口与页面
|
||||
|
||||
- [x] 5.1 新增 `frontend/src/pages/LeaderPool.tsx` 页面。
|
||||
- [x] 5.2 在 `frontend/src/App.tsx` 添加受保护路由 `/leader-pool`。
|
||||
- [x] 5.3 在 `frontend/src/components/Layout.tsx` 的 `跟单交易` 子菜单中加入 `Leader 池`,位置在 `跟单配置` 和 `Leader 管理` 之间。
|
||||
- [x] 5.4 更新 `getInitialOpenKeys` 和路径变化逻辑,使 `/leader-pool` 自动展开 `跟单交易` 菜单。
|
||||
- [x] 5.5 在 `frontend/src/locales/zh-CN/common.json`、`zh-TW/common.json`、`en/common.json` 增加 Leader 池菜单和页面基础文案。
|
||||
|
||||
## 6. Leader 池页面交互
|
||||
|
||||
- [x] 6.1 页面顶部展示池子人数、试跟中人数、估算最坏暴露和待处理风险统计卡片。
|
||||
- [x] 6.2 页面列表展示 leader 名称或地址、状态、来源、建议固定金额、建议每日最大单数、建议每日最大亏损、跟单配置状态和最后复核时间。
|
||||
- [x] 6.3 支持按状态筛选池子项,至少覆盖全部、候选、观察、小额试跟、冷却、淘汰。
|
||||
- [x] 6.4 支持从页面中把已有 leader 加入池子,并处理空列表、重复加入和 leader 不存在错误。
|
||||
- [x] 6.5 支持更新池子状态,冷却状态允许填写冷却截止时间。
|
||||
- [x] 6.6 支持编辑建议配置,保存后只更新池子建议字段。
|
||||
- [x] 6.7 支持打开 leader 的 Polymarket profile。
|
||||
- [x] 6.8 支持从池子项创建小额试跟配置,提交前展示固定金额、每日最大单数、每日最大亏损、价格区间和最大持仓确认信息。
|
||||
- [x] 6.9 创建试跟配置提交期间按钮进入 loading/disabled 状态,防止双击重复提交。
|
||||
- [x] 6.10 创建试跟配置成功后刷新池子列表,并提供跳转到 `跟单配置` 的入口。
|
||||
- [x] 6.11 创建试跟配置失败时展示后端错误,不在前端假更新状态。
|
||||
- [x] 6.12 Leader 池列表不默认逐行查询 leader 余额,避免照搬 `Leader 管理` 的重型余额加载路径。
|
||||
|
||||
## 7. Leader 管理联动
|
||||
|
||||
- [x] 7.1 在 `frontend/src/pages/LeaderList.tsx` 操作列增加 `加入 Leader 池` 操作。
|
||||
- [x] 7.2 点击加入后调用 Leader 池 add API,并对已加入池子的 leader 展示明确提示。
|
||||
- [x] 7.3 加入成功后提示用户可以前往 `Leader 池` 继续设置观察或小额试跟。
|
||||
|
||||
## 8. 测试
|
||||
|
||||
- [x] 8.1 新增后端服务测试:成功加入池子、重复加入不创建重复项、leader 不存在返回错误。
|
||||
- [x] 8.2 新增后端服务测试:并发/唯一约束重复加入被转换为明确“已在池子中”结果。
|
||||
- [x] 8.3 新增后端服务测试:状态更新、冷却截止时间保存、淘汰不删除 leader 地址。
|
||||
- [x] 8.4 新增后端服务测试:建议配置更新不修改已有 `copy_trading`。
|
||||
- [x] 8.5 新增后端服务测试:无效建议配置被拒绝且不修改原池子项。
|
||||
- [x] 8.6 新增后端服务测试:创建试跟配置使用保守默认值、默认禁用、成功后状态变为 `TRIAL`。
|
||||
- [x] 8.7 新增后端服务测试:创建试跟配置失败时池子状态不变。
|
||||
- [x] 8.8 新增后端服务测试:同账户同 leader 已有跟单配置时默认拒绝重复试跟创建。
|
||||
- [x] 8.9 新增后端服务测试:立即启用但未确认时拒绝创建跟单配置。
|
||||
- [x] 8.10 新增后端服务测试:池子列表使用批量查询路径,避免每个池子项逐条查 leader 和跟单配置。
|
||||
- [x] 8.11 新增后端控制器测试或集成测试,覆盖 list、add、update-status、update-plan、create-trial-config、remove 的主要成功和失败路径。
|
||||
- [x] 8.12 前端至少通过 TypeScript 构建验证,确保新增页面、类型、API 和菜单没有编译错误。
|
||||
- [x] 8.13 手动或自动验证前端双击创建试跟配置不会发起重复提交。
|
||||
- [x] 8.14 手动或自动验证 Leader 池列表不会默认逐行请求 leader 余额接口。
|
||||
|
||||
## 9. 文档与验证
|
||||
|
||||
- [x] 9.1 新增或更新中文文档,说明 `Leader 池` 与 `Leader 管理`、`跟单配置` 的区别。
|
||||
- [x] 9.2 文档中明确 `Leader 池` 不会自动加仓、不自动启用大额跟单、不自动抓取 leaderboard。
|
||||
- [x] 9.3 运行后端测试,至少覆盖 Leader 池相关测试。
|
||||
- [x] 9.4 运行前端构建。
|
||||
- [x] 9.5 运行前端 lint。
|
||||
- [x] 9.6 手动验证页面入口、空态、加入池子、状态更新、建议配置更新和创建小额试跟配置流程。
|
||||
Reference in New Issue
Block a user