package com.xcong.excoin.modules.okxNewPrice; import lombok.extern.slf4j.Slf4j; import java.math.BigDecimal; import java.math.RoundingMode; import java.util.ArrayList; import java.util.List; /** * 网格价格队列构建器 — 从基底入场价生成双向价格队列和 OkxGridElement 列表。 * *

职责

* * *

线程安全

* 本类为纯函数式(除 config.setStep / config.setGridElements 副作用外), * 每次调用返回新构建的对象,不持有可变状态。 * * @author Administrator */ @Slf4j public final class GridQueueBuilder { private GridQueueBuilder() { /* utility class */ } /** * 从基底入场价向下递减生成空仓价格队列,降序排列(大→小)。 * * @param config 全局配置(step 会被计算并写入) * @param basePrice 空仓基底入场价 * @return 空仓价格队列,按降序排列 */ public static List buildShortQueue(OkxConfig config, BigDecimal basePrice) { int prec = config.getPriceScale(); BigDecimal step = basePrice.multiply(config.getGridRate()).setScale(prec, RoundingMode.HALF_UP); config.setStep(step); // 其它方法依赖此 step List queue = new ArrayList<>(); BigDecimal elem = basePrice.subtract(step).setScale(prec, RoundingMode.HALF_UP); for (int i = 0; i < config.getGridQueueSize(); i++) { queue.add(elem); elem = elem.subtract(step).setScale(prec, RoundingMode.HALF_UP); if (elem.compareTo(BigDecimal.ZERO) <= 0) break; } queue.sort((a, b) -> b.compareTo(a)); // 降序 log.info("[OKX] 空队列:{}", queue); return queue; } /** * 从基底入场价向上递增生成多仓价格队列,升序排列(小→大)。 * * @param config 全局配置(使用已设置的 step) * @param basePrice 空仓基底入场价(对齐 Gate 版本,多仓队列也以此为基准) * @return 多仓价格队列,按升序排列 */ public static List buildLongQueue(OkxConfig config, BigDecimal basePrice) { int prec = config.getPriceScale(); BigDecimal step = config.getStep(); List queue = new ArrayList<>(); BigDecimal elem = basePrice.add(step).setScale(prec, RoundingMode.HALF_UP); for (int i = 0; i < config.getGridQueueSize(); i++) { queue.add(elem); elem = elem.add(step).setScale(prec, RoundingMode.HALF_UP); } queue.sort(BigDecimal::compareTo); // 升序 log.info("[OKX] 多队列:{}", queue); return queue; } /** * 将空/多仓队列整合为 OkxGridElement 列表。 *
    *
  • 空仓网格: id = -1, -2, -3 …
  • *
  • 基底网格: id = 0(短仓入场价位置)
  • *
  • 多仓网格: id = +1, +2, +3 …
  • *
* 每个网格元素包含两个方向的 {@link OkxTraderParam}(入场价 / 止盈价 / 数量)。 * * @param config 全局配置 * @param shortQueue 空仓价格队列 * @param longQueue 多仓价格队列 * @param basePrice 空仓基底入场价 * @return 构建好的网格元素列表(已注入 config) */ public static List buildGridElements(OkxConfig config, List shortQueue, List longQueue, BigDecimal basePrice) { List elements = new ArrayList<>(); int shortSize = shortQueue.size(); int longSize = longQueue.size(); int prec = config.getPriceScale(); BigDecimal step = config.getStep(); String qty = config.getQuantity(); // ---- 空仓网格: id = -1, -2, … ---- for (int i = 0; i < shortSize; i++) { int id = -(i + 1); Integer upId = (i == 0) ? 0 : id + 1; Integer downId = (i == shortSize - 1) ? null : id - 1; BigDecimal price = shortQueue.get(i); OkxTraderParam longParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.LONG) .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); OkxTraderParam shortParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.SHORT) .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); elements.add(OkxGridElement.builder().id(id).gridPrice(price).upId(upId).downId(downId) .longTraderParam(longParam).shortTraderParam(shortParam).build()); } // ---- 基底网格: id = 0 ---- { BigDecimal price = basePrice; OkxTraderParam longParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.LONG) .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); OkxTraderParam shortParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.SHORT) .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); elements.add(OkxGridElement.builder().id(0).gridPrice(price) .upId(shortSize > 0 ? 1 : null).downId(longSize > 0 ? -1 : null) .longTraderParam(longParam).shortTraderParam(shortParam).build()); } // ---- 多仓网格: id = 1, 2, … ---- for (int i = 0; i < longSize; i++) { int id = i + 1; Integer downId = (i == 0) ? 0 : id - 1; Integer upId = (i == longSize - 1) ? null : id + 1; BigDecimal price = longQueue.get(i); OkxTraderParam longParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.LONG) .entryPrice(price).takeProfitPrice(price.add(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); OkxTraderParam shortParam = OkxTraderParam.builder() .direction(OkxTraderParam.Direction.SHORT) .entryPrice(price).takeProfitPrice(price.subtract(step).setScale(prec, RoundingMode.HALF_UP)).quantity(qty).build(); elements.add(OkxGridElement.builder().id(id).gridPrice(price).upId(upId).downId(downId) .longTraderParam(longParam).shortTraderParam(shortParam).build()); } config.setGridElements(elements); log.info("[OKX] 网格元素列表已构建, 共{}个元素", elements.size()); return elements; } }