- 尾盘策略 CRUD、订单簿 WS 订阅、周期内触发下单 - 订单簿订阅日志增加市场 slug,便于排查 - 移除轮询,完全依赖 WebSocket(删除 CryptoTailStrategyScheduler) - FIXED 模式数量改为小数、向上取整,与签名服务一致 - 前端策略列表页、多语言与 API 对接 Co-authored-by: Cursor <cursoragent@cursor.com>
205 lines
11 KiB
Markdown
205 lines
11 KiB
Markdown
# 加密市场尾盘策略 - 流程图
|
||
|
||
## 一、整体架构
|
||
|
||
```
|
||
┌─────────────────┐ POST 创建/更新 ┌──────────────────────────┐
|
||
│ 前端 / API │ ──────────────────────►│ CryptoTailStrategyController│
|
||
└─────────────────┘ └──────────────┬─────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────┐
|
||
│ CryptoTailStrategyService │
|
||
│ create / update │
|
||
│ save → publishEvent │
|
||
└──────────────┬─────────────┘
|
||
│
|
||
┌─────────────────────────────────────────┼─────────────────────────────────────────┐
|
||
│ CryptoTailStrategyChangedEvent │ │
|
||
▼ ▼ ▼
|
||
┌──────────────────────────────┐ ┌──────────────────────────────┐ ┌──────────────────────────────┐
|
||
│ CryptoTailStrategyScheduler │ │ CryptoTailOrderbookWsService │ │ (其他监听方,如有) │
|
||
│ @EventListener │ │ @EventListener │ └──────────────────────────────┘
|
||
│ → runCycle() 一次(补充) │ │ → refreshAndSubscribe() │
|
||
└──────────────┬───────────────┘ └──────────────┬───────────────┘
|
||
│ │
|
||
▼ │
|
||
┌──────────────────────────────┐ │
|
||
│ CryptoTailStrategyExecution │ │ 每 25 秒 + 事件时
|
||
│ runCycle() │ │ refreshAndSubscribe()
|
||
│ (HTTP 拉订单簿,满足则下单) │ ▼
|
||
└──────────────────────────────┘ ┌──────────────────────────────┐
|
||
│ CLOB Market WebSocket │
|
||
│ wss://.../ws/market │
|
||
│ subscribe assets_ids │
|
||
└──────────────┬───────────────┘
|
||
│ book / price_change
|
||
▼
|
||
┌──────────────────────────────┐
|
||
│ onBestBid(tokenId, bestBid) │
|
||
│ → tryTriggerWithPriceFromWs │
|
||
└──────────────┬───────────────┘
|
||
│
|
||
▼
|
||
┌──────────────────────────────┐
|
||
│ CryptoTailStrategyExecution │
|
||
│ placeOrderForTrigger │
|
||
│ → CLOB 下单 + 写触发记录 │
|
||
└──────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 二、策略创建/更新流程(API → 事件)
|
||
|
||
```mermaid
|
||
sequenceDiagram
|
||
participant API as Controller
|
||
participant Svc as CryptoTailStrategyService
|
||
participant DB as DB
|
||
participant Event as ApplicationEventPublisher
|
||
|
||
API->>Svc: create(request) / update(request)
|
||
Svc->>Svc: 参数校验(账户、窗口、价格、金额模式等)
|
||
Svc->>DB: save(entity)
|
||
Svc->>Event: publishEvent(CryptoTailStrategyChangedEvent)
|
||
Svc->>API: Result.success(dto)
|
||
```
|
||
|
||
- **创建**:校验通过后落库,发布 `CryptoTailStrategyChangedEvent`,返回 DTO。
|
||
- **更新**:同上,更新实体后发布同一事件。
|
||
- **删除**:不发布事件(策略已移除,WS 下次刷新订阅时会自然不再包含该策略)。
|
||
|
||
---
|
||
|
||
## 三、策略变更后:双路响应
|
||
|
||
事件发出后,两个监听方并行执行,互不阻塞:
|
||
|
||
| 监听方 | 动作 | 说明 |
|
||
|--------|------|------|
|
||
| **CryptoTailStrategyScheduler** | `onStrategyChanged` → `runCycle()` 一次 | 用 HTTP 拉订单簿做一轮检查,作为 WS 未就绪时的补充。 |
|
||
| **CryptoTailOrderbookWsService** | `onStrategyChanged` → `refreshAndSubscribe()` | 按当前启用策略重新算 token 列表,向 WS 发送新的 `assets_ids` 订阅。 |
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph 事件
|
||
E[CryptoTailStrategyChangedEvent]
|
||
end
|
||
subgraph 调度器
|
||
S[Scheduler.onStrategyChanged]
|
||
R[executionService.runCycle]
|
||
S --> R
|
||
end
|
||
subgraph WS服务
|
||
W[OrderbookWsService.onStrategyChanged]
|
||
Ref[refreshAndSubscribe]
|
||
W --> Ref
|
||
end
|
||
E --> S
|
||
E --> W
|
||
```
|
||
|
||
---
|
||
|
||
## 四、WebSocket 订单簿监听流程(主路径)
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph 启动与连接
|
||
A[PostConstruct init] --> B[connect]
|
||
B --> C[OkHttp WebSocket 连接 wss://.../ws/market]
|
||
C --> D[onOpen: refreshAndSubscribe]
|
||
end
|
||
|
||
subgraph 订阅维护
|
||
D --> E[buildSubscriptionMap]
|
||
E --> F[遍历 enabled 策略]
|
||
F --> G[当前周期 periodStartUnix]
|
||
G --> H[slug = prefix-periodStartUnix]
|
||
H --> I[Gamma getEventBySlug]
|
||
I --> J[得到 tokenIds]
|
||
J --> K[tokenId → List of WsBookEntry]
|
||
K --> L[发送 type=MARKET, assets_ids=[...]]
|
||
T[每 25 秒 @Scheduled] --> E
|
||
EV[onStrategyChanged] --> E
|
||
end
|
||
|
||
subgraph 收消息与触发
|
||
M[onMessage: book / price_change]
|
||
M --> N[解析 asset_id, best_bid]
|
||
N --> O[onBestBid tokenId, bestBid]
|
||
O --> P[查 tokenToEntries 得到策略列表]
|
||
P --> Q[筛时间窗内]
|
||
Q --> R[scope.launch tryTriggerWithPriceFromWs]
|
||
R --> S[placeOrderForTrigger]
|
||
end
|
||
|
||
L --> M
|
||
```
|
||
|
||
- **buildSubscriptionMap**:只包含「当前时间仍在窗口内」的策略(`nowSeconds < windowEnd`),并只订阅这些策略对应周期的 token。
|
||
- **onBestBid**:再按当前时间过滤一次时间窗,对每个命中策略在协程里调用 `tryTriggerWithPriceFromWs`,内部会查「本周期是否已触发」和价格区间,通过则 `placeOrderForTrigger`。
|
||
|
||
---
|
||
|
||
## 五、执行层:下单条件与顺序(ExecutionService)
|
||
|
||
无论来自 **runCycle(HTTP)** 还是 **tryTriggerWithPriceFromWs(WS)**,最终都走同一套下单逻辑。
|
||
|
||
```mermaid
|
||
flowchart TB
|
||
subgraph runCycle 入口
|
||
A[runCycle] --> B[findAllByEnabledTrue]
|
||
B --> C[processStrategy 每个策略]
|
||
C --> D[在时间窗? 本周期已触发?]
|
||
D --> E[Gamma getEventBySlug]
|
||
E --> F[HTTP getOrderbook 两个 token]
|
||
F --> G[第一个 bestBid 在 minPrice~maxPrice?]
|
||
G --> H[placeOrderForTrigger]
|
||
end
|
||
|
||
subgraph tryTriggerWithPriceFromWs 入口
|
||
I[WS onBestBid] --> J[tryTriggerWithPriceFromWs]
|
||
J --> K[本周期已触发? bestBid 在区间?]
|
||
K --> H
|
||
end
|
||
|
||
subgraph placeOrderForTrigger 统一
|
||
H --> L[账户、API 凭证]
|
||
L --> M[余额、下单金额]
|
||
M --> N[最优价、数量]
|
||
N --> O[签名、CLOB 下单]
|
||
O --> P[保存 CryptoTailStrategyTrigger]
|
||
end
|
||
```
|
||
|
||
- **每周期最多触发一次**:由 `triggerRepository.findByStrategyIdAndPeriodStartUnix` 保证。
|
||
- **价格区间**:`minPrice ≤ bestBid ≤ maxPrice` 才触发。
|
||
- **时间窗**:仅当 `windowStart ≤ now < windowEnd`(以当前周期的 `periodStartUnix` 为基准)才参与检查/下单。
|
||
|
||
---
|
||
|
||
## 六、关键数据流小结
|
||
|
||
| 阶段 | 输入 | 输出/动作 |
|
||
|------|------|-----------|
|
||
| 创建/更新策略 | API 请求体 | 落库 + 发布 `CryptoTailStrategyChangedEvent` |
|
||
| 事件 → 调度器 | 事件 | 执行一次 `runCycle()`(HTTP 拉订单簿,满足则下单) |
|
||
| 事件 → WS 服务 | 事件 | `refreshAndSubscribe()`,更新订阅的 `assets_ids` |
|
||
| 定时刷新订阅 | 每 25 秒 | `refreshAndSubscribe()`,保证新周期、新策略被订阅 |
|
||
| WS 收 book/price_change | asset_id, best_bid | `onBestBid` → 时间窗内策略 → `tryTriggerWithPriceFromWs` → 未触发且价格在区间则 `placeOrderForTrigger` |
|
||
| placeOrderForTrigger | 策略、周期、token、outcome、价格 | 账户/余额/价格/签名 → CLOB 下单 → 写触发记录 |
|
||
|
||
---
|
||
|
||
## 七、涉及类与职责
|
||
|
||
| 类 | 职责 |
|
||
|----|------|
|
||
| **CryptoTailStrategyController** | 接收 list/create/update/delete/triggers/marketOptions 的 POST。 |
|
||
| **CryptoTailStrategyService** | 策略 CRUD、校验、发布 `CryptoTailStrategyChangedEvent`。 |
|
||
| **CryptoTailStrategyScheduler** | 监听策略变更事件,执行一次 `runCycle()`。 |
|
||
| **CryptoTailOrderbookWsService** | 连接 CLOB Market WS、维护订阅(事件 + 每 25 秒)、处理 book/price_change、调用 `tryTriggerWithPriceFromWs`。 |
|
||
| **CryptoTailStrategyExecutionService** | `runCycle()`(HTTP 路径)、`tryTriggerWithPriceFromWs()`(WS 路径)、`placeOrderForTrigger()`(统一下单与写触发记录)。 |
|