Files
PolyHermes/docs/zh/crypto-tail-strategy-flow.md
T
WrBugandCursor 2238370088 feat(crypto-tail): 尾盘策略完整实现与优化
- 尾盘策略 CRUD、订单簿 WS 订阅、周期内触发下单
- 订单簿订阅日志增加市场 slug,便于排查
- 移除轮询,完全依赖 WebSocket(删除 CryptoTailStrategyScheduler)
- FIXED 模式数量改为小数、向上取整,与签名服务一致
- 前端策略列表页、多语言与 API 对接

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-14 05:01:10 +08:00

11 KiB
Raw Blame History

加密市场尾盘策略 - 流程图

一、整体架构

┌─────────────────┐     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 → 事件)

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 onStrategyChangedrunCycle() 一次 用 HTTP 拉订单簿做一轮检查,作为 WS 未就绪时的补充。
CryptoTailOrderbookWsService onStrategyChangedrefreshAndSubscribe() 按当前启用策略重新算 token 列表,向 WS 发送新的 assets_ids 订阅。
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 订单簿监听流程(主路径)

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

无论来自 runCycleHTTP 还是 tryTriggerWithPriceFromWsWS,最终都走同一套下单逻辑。

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()(统一下单与写触发记录)。