Administrator
2026-06-05 1b55621d4dcf3b4ee6b9c4beb81ad69e5b7a5856
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
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 列表。
 *
 * <h3>职责</h3>
 * <ul>
 *   <li>根据基底空头入场价,向下递减排空仓队列</li>
 *   <li>向上递增排多仓队列</li>
 *   <li>整合两队列为 OkxGridElement 列表并注入 {@link OkxConfig}</li>
 * </ul>
 *
 * <h3>线程安全</h3>
 * 本类为纯函数式(除 config.setStep / config.setGridElements 副作用外),
 * 每次调用返回新构建的对象,不持有可变状态。
 *
 * @author Administrator
 */
@Slf4j
public final class GridQueueBuilder {
 
    private GridQueueBuilder() { /* utility class */ }
 
    /**
     * 从基底入场价向下递减生成空仓价格队列,降序排列(大→小)。
     *
     * @param config   全局配置(step 会被计算并写入)
     * @param basePrice 空仓基底入场价
     * @return 空仓价格队列,按降序排列
     */
    public static List<BigDecimal> 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<BigDecimal> 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<BigDecimal> buildLongQueue(OkxConfig config, BigDecimal basePrice) {
        int prec = config.getPriceScale();
        BigDecimal step = config.getStep();
        List<BigDecimal> 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 列表。
     * <ul>
     *   <li>空仓网格: id = -1, -2, -3 …</li>
     *   <li>基底网格: id = 0(短仓入场价位置)</li>
     *   <li>多仓网格: id = +1, +2, +3 …</li>
     * </ul>
     * 每个网格元素包含两个方向的 {@link OkxTraderParam}(入场价 / 止盈价 / 数量)。
     *
     * @param config     全局配置
     * @param shortQueue 空仓价格队列
     * @param longQueue  多仓价格队列
     * @param basePrice  空仓基底入场价
     * @return 构建好的网格元素列表(已注入 config)
     */
    public static List<OkxGridElement> buildGridElements(OkxConfig config,
                                                          List<BigDecimal> shortQueue,
                                                          List<BigDecimal> longQueue,
                                                          BigDecimal basePrice) {
        List<OkxGridElement> 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;
    }
}