# 加密价差策略 - 流程图

## 一、整体架构

```
┌─────────────────┐     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()`（统一下单与写触发记录）。 |
