Administrator
2026-06-05 3c86df8d1170406ca3ca036d1337e8654ab5d41a
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
package com.xcong.excoin.modules.okxNewPrice;
 
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
 
/**
 * 网格价格层级,策略的最小操作单元。
 *
 * <h3>定位</h3>
 * 每个 OkxGridElement 对应网格中的一个价格点,同时持有该点的多仓和空仓挂单状态。
 * 维护全局静态 HashMap 索引实现 O(1) 双向查询。
 *
 * <h3>ID 体系与链表</h3>
 * <pre>
 *   ID ≦ -1:  空仓队列区域(降序),ID 自减,gridPrice 递减
 *   ID  =  0:  基座位置,gridPrice = shortBaseEntryPrice
 *   ID ≧  1:  多仓队列区域(升序),ID 自增,gridPrice 递增
 *
 *   链表: ... ← -3 ← -2 ← -1 ← 0 → 1 → 2 → 3 → ...
 * </pre>
 *
 * <h3>8 个全局 O(1) 索引</h3>
 * <pre>
 *   INDEX                 → findById(int)               ID → 元素
 *   PRICE_INDEX           → findByPrice(BigDecimal)     价格 → 元素
 *   LONG_ORDER_ID_INDEX   → findByLongOrderId(String)   多仓挂单ID → 元素
 *   SHORT_ORDER_ID_INDEX  → findByShortOrderId(String)  空仓挂单ID → 元素
 *   LONG_TP_ORDER_ID_INDEX→ findByLongTakeProfitOrderId(String)  多止盈ID → 元素
 *   SHORT_TP_ORDER_ID_INDEX→ findByShortTakeProfitOrderId(String) 空止盈ID → 元素
 *   LONG_SL_ORDER_ID_INDEX→ findByLongStopLossOrderId(String)    多止损ID → 元素
 *   SHORT_SL_ORDER_ID_INDEX→ findByShortStopLossOrderId(String)  空止损ID → 元素
 * </pre>
 *
 * @author Administrator
 */
public class OkxGridElement {
 
    private int id;
    private BigDecimal gridPrice;
    private boolean hasLongOrder;
    private boolean hasShortOrder;
    private OkxTraderParam longTraderParam;
    private OkxTraderParam shortTraderParam;
    private Integer upId;
    private Integer downId;
    private String longOrderId;
    private String shortOrderId;
    private String longTakeProfitOrderId;
    private String shortTakeProfitOrderId;
    private String longStopLossOrderId;
    private String shortStopLossOrderId;
 
    // ==================== 全局索引 ====================
    private static final Map<Integer, OkxGridElement> INDEX = new ConcurrentHashMap<>();
    private static final Map<BigDecimal, OkxGridElement> PRICE_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> LONG_ORDER_ID_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> SHORT_ORDER_ID_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> LONG_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> SHORT_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> LONG_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
    private static final Map<String, OkxGridElement> SHORT_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>();
 
    // ==================== 静态查找方法 ====================
 
    public static OkxGridElement findById(int id) {
        return INDEX.get(id);
    }
 
    public static OkxGridElement findByPrice(BigDecimal price) {
        return PRICE_INDEX.get(price);
    }
 
    public static OkxGridElement findByLongOrderId(String orderId) {
        return LONG_ORDER_ID_INDEX.get(orderId);
    }
 
    public static OkxGridElement findByShortOrderId(String orderId) {
        return SHORT_ORDER_ID_INDEX.get(orderId);
    }
 
    public static OkxGridElement findByLongTakeProfitOrderId(String orderId) {
        return LONG_TP_ORDER_ID_INDEX.get(orderId);
    }
 
    public static OkxGridElement findByShortTakeProfitOrderId(String orderId) {
        return SHORT_TP_ORDER_ID_INDEX.get(orderId);
    }
 
    public static OkxGridElement findByLongStopLossOrderId(String orderId) {
        return LONG_SL_ORDER_ID_INDEX.get(orderId);
    }
 
    public static OkxGridElement findByShortStopLossOrderId(String orderId) {
        return SHORT_SL_ORDER_ID_INDEX.get(orderId);
    }
 
    /**
     * 全量重建全局索引。由 OkxConfig.setGridElements() 调用。
     */
    public static void rebuildIndex(List<OkxGridElement> elements) {
        INDEX.clear();
        PRICE_INDEX.clear();
        LONG_ORDER_ID_INDEX.clear();
        SHORT_ORDER_ID_INDEX.clear();
        LONG_TP_ORDER_ID_INDEX.clear();
        SHORT_TP_ORDER_ID_INDEX.clear();
        LONG_SL_ORDER_ID_INDEX.clear();
        SHORT_SL_ORDER_ID_INDEX.clear();
        for (OkxGridElement e : elements) {
            INDEX.put(e.getId(), e);
            putDynamicIndices(e);
        }
        logAll();
    }
 
    /**
     * 增量刷新动态索引。每次修改订单状态后调用。
     */
    public static void refreshIndices() {
        PRICE_INDEX.clear();
        LONG_ORDER_ID_INDEX.clear();
        SHORT_ORDER_ID_INDEX.clear();
        LONG_TP_ORDER_ID_INDEX.clear();
        SHORT_TP_ORDER_ID_INDEX.clear();
        LONG_SL_ORDER_ID_INDEX.clear();
        SHORT_SL_ORDER_ID_INDEX.clear();
        for (OkxGridElement e : INDEX.values()) {
            putDynamicIndices(e);
        }
        logAll();
    }
 
    /**
     * 获取所有已挂空仓条件单且当前价高于其价格、无止盈单的网格元素。
     */
    public static List<OkxGridElement> findAllLongOrders(BigDecimal currentPrice) {
        List<OkxGridElement> result = new ArrayList<>();
        for (OkxGridElement e : INDEX.values()) {
            if (e.isHasLongOrder() && e.getGridPrice().compareTo(currentPrice) > 0 && e.getLongTakeProfitOrderId() == null) {
                result.add(e);
            }
        }
        return result;
    }
 
    /**
     * 获取所有已挂多仓条件单且当前价低于其价格、无止盈单的网格元素。
     */
    public static List<OkxGridElement> findAllShortOrders(BigDecimal currentPrice) {
        List<OkxGridElement> result = new ArrayList<>();
        for (OkxGridElement e : INDEX.values()) {
            if (e.isHasShortOrder() && e.getGridPrice().compareTo(currentPrice) < 0 && e.getShortTakeProfitOrderId() == null) {
                result.add(e);
            }
        }
        return result;
    }
 
    private static void putDynamicIndices(OkxGridElement e) {
        PRICE_INDEX.put(e.getGridPrice(), e);
        if (e.getLongOrderId() != null) LONG_ORDER_ID_INDEX.put(e.getLongOrderId(), e);
        if (e.getShortOrderId() != null) SHORT_ORDER_ID_INDEX.put(e.getShortOrderId(), e);
        if (e.getLongTakeProfitOrderId() != null) LONG_TP_ORDER_ID_INDEX.put(e.getLongTakeProfitOrderId(), e);
        if (e.getShortTakeProfitOrderId() != null) SHORT_TP_ORDER_ID_INDEX.put(e.getShortTakeProfitOrderId(), e);
        if (e.getLongStopLossOrderId() != null) LONG_SL_ORDER_ID_INDEX.put(e.getLongStopLossOrderId(), e);
        if (e.getShortStopLossOrderId() != null) SHORT_SL_ORDER_ID_INDEX.put(e.getShortStopLossOrderId(), e);
    }
 
    public static void logAll() {
        List<OkxGridElement> sorted = new ArrayList<>(INDEX.values());
        sorted.sort((a, b) -> Integer.compare(a.getId(), b.getId()));
        StringBuilder sb = new StringBuilder("\n========== OKX 网格数据 ==========\n");
        for (OkxGridElement e : sorted) {
            if (e.isHasLongOrder() || e.isHasShortOrder()
                    || e.getLongStopLossOrderId() != null || e.getShortStopLossOrderId() != null) {
                sb.append(String.format(
                        "  ID=%4d  价格=%s  up=%s  down=%s  多仓=%s(%s)  空仓=%s(%s)  多止盈=%s  空止盈=%s  多止损=%s  空止损=%s\n",
                        e.getId(), e.getGridPrice(), e.getUpId(), e.getDownId(),
                        e.isHasLongOrder() ? "有" : "无", e.getLongOrderId() != null ? e.getLongOrderId() : "-",
                        e.isHasShortOrder() ? "有" : "无", e.getShortOrderId() != null ? e.getShortOrderId() : "-",
                        e.getLongTakeProfitOrderId() != null ? e.getLongTakeProfitOrderId() : "-",
                        e.getShortTakeProfitOrderId() != null ? e.getShortTakeProfitOrderId() : "-",
                        e.getLongStopLossOrderId() != null ? e.getLongStopLossOrderId() : "-",
                        e.getShortStopLossOrderId() != null ? e.getShortStopLossOrderId() : "-"));
            }
        }
        sb.append(String.format(
                "  索引统计: ID=%d  价格=%d  多仓订单ID=%d  空仓订单ID=%d  多止盈ID=%d  空止盈ID=%d  多止损ID=%d  空止损ID=%d\n",
                INDEX.size(), PRICE_INDEX.size(), LONG_ORDER_ID_INDEX.size(), SHORT_ORDER_ID_INDEX.size(),
                LONG_TP_ORDER_ID_INDEX.size(), SHORT_TP_ORDER_ID_INDEX.size(),
                LONG_SL_ORDER_ID_INDEX.size(), SHORT_SL_ORDER_ID_INDEX.size()));
        sb.append("================================\n");
        System.out.println(sb);
    }
 
    public OkxGridElement getUp() {
        return upId != null ? INDEX.get(upId) : null;
    }
 
    public OkxGridElement getDown() {
        return downId != null ? INDEX.get(downId) : null;
    }
 
    private OkxGridElement(Builder builder) {
        this.id = builder.id;
        this.gridPrice = builder.gridPrice;
        this.hasLongOrder = builder.hasLongOrder;
        this.hasShortOrder = builder.hasShortOrder;
        this.longTraderParam = builder.longTraderParam;
        this.shortTraderParam = builder.shortTraderParam;
        this.upId = builder.upId;
        this.downId = builder.downId;
        this.longOrderId = builder.longOrderId;
        this.shortOrderId = builder.shortOrderId;
        this.longTakeProfitOrderId = builder.longTakeProfitOrderId;
        this.shortTakeProfitOrderId = builder.shortTakeProfitOrderId;
        this.longStopLossOrderId = builder.longStopLossOrderId;
        this.shortStopLossOrderId = builder.shortStopLossOrderId;
    }
 
    // ==================== getters/setters ====================
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public BigDecimal getGridPrice() { return gridPrice; }
    public void setGridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; }
    public boolean isHasLongOrder() { return hasLongOrder; }
    public void setHasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; }
    public boolean isHasShortOrder() { return hasShortOrder; }
    public void setHasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; }
    public OkxTraderParam getLongTraderParam() { return longTraderParam; }
    public void setLongTraderParam(OkxTraderParam longTraderParam) { this.longTraderParam = longTraderParam; }
    public OkxTraderParam getShortTraderParam() { return shortTraderParam; }
    public void setShortTraderParam(OkxTraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; }
    public Integer getUpId() { return upId; }
    public void setUpId(Integer upId) { this.upId = upId; }
    public Integer getDownId() { return downId; }
    public void setDownId(Integer downId) { this.downId = downId; }
    public String getLongOrderId() { return longOrderId; }
    public void setLongOrderId(String longOrderId) { this.longOrderId = longOrderId; }
    public String getShortOrderId() { return shortOrderId; }
    public void setShortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; }
    public String getLongTakeProfitOrderId() { return longTakeProfitOrderId; }
    public void setLongTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; }
    public String getShortTakeProfitOrderId() { return shortTakeProfitOrderId; }
    public void setShortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; }
    public String getLongStopLossOrderId() { return longStopLossOrderId; }
    public void setLongStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; }
    public String getShortStopLossOrderId() { return shortStopLossOrderId; }
    public void setShortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; }
 
    public static Builder builder() {
        return new Builder();
    }
 
    public static class Builder {
        private int id;
        private BigDecimal gridPrice;
        private boolean hasLongOrder = false;
        private boolean hasShortOrder = false;
        private OkxTraderParam longTraderParam;
        private OkxTraderParam shortTraderParam;
        private Integer upId;
        private Integer downId;
        private String longOrderId;
        private String shortOrderId;
        private String longTakeProfitOrderId;
        private String shortTakeProfitOrderId;
        private String longStopLossOrderId;
        private String shortStopLossOrderId;
 
        public Builder id(int id) { this.id = id; return this; }
        public Builder gridPrice(BigDecimal gridPrice) { this.gridPrice = gridPrice; return this; }
        public Builder hasLongOrder(boolean hasLongOrder) { this.hasLongOrder = hasLongOrder; return this; }
        public Builder hasShortOrder(boolean hasShortOrder) { this.hasShortOrder = hasShortOrder; return this; }
        public Builder longTraderParam(OkxTraderParam longTraderParam) { this.longTraderParam = longTraderParam; return this; }
        public Builder shortTraderParam(OkxTraderParam shortTraderParam) { this.shortTraderParam = shortTraderParam; return this; }
        public Builder upId(Integer upId) { this.upId = upId; return this; }
        public Builder downId(Integer downId) { this.downId = downId; return this; }
        public Builder longOrderId(String longOrderId) { this.longOrderId = longOrderId; return this; }
        public Builder shortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; return this; }
        public Builder longTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; return this; }
        public Builder shortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; return this; }
        public Builder longStopLossOrderId(String longStopLossOrderId) { this.longStopLossOrderId = longStopLossOrderId; return this; }
        public Builder shortStopLossOrderId(String shortStopLossOrderId) { this.shortStopLossOrderId = shortStopLossOrderId; return this; }
 
        public OkxGridElement build() {
            return new OkxGridElement(this);
        }
    }
}