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 列表。
*
*
职责
*
* - 根据基底空头入场价,向下递减排空仓队列
* - 向上递增排多仓队列
* - 整合两队列为 OkxGridElement 列表并注入 {@link OkxConfig}
*
*
* 线程安全
* 本类为纯函数式(除 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;
}
}