| | |
| | | private Integer upId; |
| | | /** 下一个网格编号,null 表示无下一级 */ |
| | | private Integer downId; |
| | | /** 多仓挂单订单 ID */ |
| | | private String longOrderId; |
| | | /** 空仓挂单订单 ID */ |
| | | private String shortOrderId; |
| | | /** 多仓挂单订单 ID 列表(支持同一网格多个挂单,由止损追单产生) */ |
| | | private List<String> longOrderIds = new ArrayList<>(); |
| | | /** 空仓挂单订单 ID 列表(支持同一网格多个挂单,由止损追单产生) */ |
| | | private List<String> shortOrderIds = new ArrayList<>(); |
| | | /** 多仓止盈订单 ID */ |
| | | private String longTakeProfitOrderId; |
| | | /** 空仓止盈订单 ID */ |
| | | private String shortTakeProfitOrderId; |
| | | /** 多仓止损订单 ID 列表(支持一个网格多个止损单) */ |
| | | private List<String> longStopLossOrderIds = new ArrayList<>(); |
| | | /** 空仓止损订单 ID 列表(支持一个网格多个止损单) */ |
| | | private List<String> shortStopLossOrderIds = new ArrayList<>(); |
| | | |
| | | /** 索引重建锁,保证 refreshIndices() 与计数读取之间互斥,避免 clear→rebuild 窗口期读到 0 */ |
| | | private static final Object INDEX_LOCK = new Object(); |
| | | |
| | | /** 全局 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */ |
| | | private static final Map<Integer, GridElement> INDEX = new ConcurrentHashMap<>(); |
| | |
| | | private static final Map<String, GridElement> LONG_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>(); |
| | | /** 全局空仓止盈订单 ID 索引,由 {@link GateConfig#setGridElements(List)} 触发重建,O(1) 查找 */ |
| | | private static final Map<String, GridElement> SHORT_TP_ORDER_ID_INDEX = new ConcurrentHashMap<>(); |
| | | /** 全局多仓止损订单 ID 索引 */ |
| | | private static final Map<String, GridElement> LONG_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>(); |
| | | /** 全局空仓止损订单 ID 索引 */ |
| | | private static final Map<String, GridElement> SHORT_SL_ORDER_ID_INDEX = new ConcurrentHashMap<>(); |
| | | |
| | | /** |
| | | * 根据 ID 快速查找网格元素(O(1))。 |
| | |
| | | return SHORT_TP_ORDER_ID_INDEX.get(orderId); |
| | | } |
| | | |
| | | /** @return 当前多仓止盈单数量(与 refreshIndices 互斥,避免清空窗口读到 0) */ |
| | | public static int getLongTakeProfitCount() { |
| | | synchronized (INDEX_LOCK) { return LONG_TP_ORDER_ID_INDEX.size(); } |
| | | } |
| | | |
| | | /** @return 当前空仓止盈单数量(与 refreshIndices 互斥,避免清空窗口读到 0) */ |
| | | public static int getShortTakeProfitCount() { |
| | | synchronized (INDEX_LOCK) { return SHORT_TP_ORDER_ID_INDEX.size(); } |
| | | } |
| | | |
| | | /** |
| | | * 根据多仓止损订单 ID 快速查找网格元素(O(1))。 |
| | | */ |
| | | public static GridElement findByLongStopLossOrderId(String orderId) { |
| | | return LONG_SL_ORDER_ID_INDEX.get(orderId); |
| | | } |
| | | |
| | | /** |
| | | * 根据空仓止损订单 ID 快速查找网格元素(O(1))。 |
| | | */ |
| | | public static GridElement findByShortStopLossOrderId(String orderId) { |
| | | return SHORT_SL_ORDER_ID_INDEX.get(orderId); |
| | | } |
| | | |
| | | /** |
| | | * 从列表中重建全局 ID 索引和价格索引。 |
| | | * 由 {@link GateConfig#setGridElements(List)} 在每次列表变更后调用。 |
| | |
| | | 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 (GridElement e : elements) { |
| | | INDEX.put(e.getId(), e); |
| | | putDynamicIndices(e); |
| | |
| | | * 使快速查找方法获取到最新数据。 |
| | | */ |
| | | 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(); |
| | | for (GridElement e : INDEX.values()) { |
| | | putDynamicIndices(e); |
| | | synchronized (INDEX_LOCK) { |
| | | 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 (GridElement e : INDEX.values()) { |
| | | putDynamicIndices(e); |
| | | } |
| | | } |
| | | // logAll 在锁外执行,不阻塞计数查询 |
| | | logAll(); |
| | | } |
| | | |
| | |
| | | sorted.sort((a, b) -> Integer.compare(a.getId(), b.getId())); |
| | | StringBuilder sb = new StringBuilder("\n========== 网格数据 ==========\n"); |
| | | for (GridElement e : sorted) { |
| | | if (e.isHasLongOrder() || e.isHasShortOrder()){ |
| | | if (e.isHasLongOrder() || e.isHasShortOrder() |
| | | || e.hasLongStopLossOrders() || e.hasShortStopLossOrders()){ |
| | | sb.append(String.format( |
| | | " ID=%4d 价格=%s up=%s down=%s 多仓=%s(%s) 空仓=%s(%s) 多止盈=%s 空止盈=%s\n", |
| | | " 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.hasLongOrderIds() ? String.join(",", e.getLongOrderIds()) : "-", |
| | | e.isHasShortOrder() ? "有" : "无", |
| | | e.getShortOrderId() != null ? e.getShortOrderId() : "-", |
| | | e.hasShortOrderIds() ? String.join(",", e.getShortOrderIds()) : "-", |
| | | e.getLongTakeProfitOrderId() != null ? e.getLongTakeProfitOrderId() : "-", |
| | | e.getShortTakeProfitOrderId() != null ? e.getShortTakeProfitOrderId() : "-" |
| | | e.getShortTakeProfitOrderId() != null ? e.getShortTakeProfitOrderId() : "-", |
| | | e.hasLongStopLossOrders() ? String.join(",", e.getLongStopLossOrderIds()) : "-", |
| | | e.hasShortStopLossOrders() ? String.join(",", e.getShortStopLossOrderIds()) : "-" |
| | | )); |
| | | } |
| | | } |
| | | sb.append(String.format( |
| | | "------------------------------------------------------------\n" + |
| | | " 索引统计: ID=%d 价格=%d 多仓订单ID=%d 空仓订单ID=%d 多止盈ID=%d 空止盈ID=%d\n", |
| | | " 索引统计: 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() |
| | | SHORT_TP_ORDER_ID_INDEX.size(), |
| | | LONG_SL_ORDER_ID_INDEX.size(), |
| | | SHORT_SL_ORDER_ID_INDEX.size() |
| | | )); |
| | | sb.append(String.format(" 多仓订单ID索引: %s\n", LONG_ORDER_ID_INDEX.keySet())); |
| | | sb.append(String.format(" 空仓订单ID索引: %s\n", SHORT_ORDER_ID_INDEX.keySet())); |
| | |
| | | |
| | | private static void putDynamicIndices(GridElement e) { |
| | | PRICE_INDEX.put(e.getGridPrice(), e); |
| | | if (e.getLongOrderId() != null) { |
| | | LONG_ORDER_ID_INDEX.put(e.getLongOrderId(), e); |
| | | for (String oId : e.getLongOrderIds()) { |
| | | LONG_ORDER_ID_INDEX.put(oId, e); |
| | | } |
| | | if (e.getShortOrderId() != null) { |
| | | SHORT_ORDER_ID_INDEX.put(e.getShortOrderId(), e); |
| | | for (String oId : e.getShortOrderIds()) { |
| | | SHORT_ORDER_ID_INDEX.put(oId, 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); |
| | | } |
| | | for (String slId : e.getLongStopLossOrderIds()) { |
| | | LONG_SL_ORDER_ID_INDEX.put(slId, e); |
| | | } |
| | | for (String slId : e.getShortStopLossOrderIds()) { |
| | | SHORT_SL_ORDER_ID_INDEX.put(slId, e); |
| | | } |
| | | } |
| | | |
| | |
| | | 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; |
| | | if (builder.longOrderIds != null) this.longOrderIds.addAll(builder.longOrderIds); |
| | | if (builder.shortOrderIds != null) this.shortOrderIds.addAll(builder.shortOrderIds); |
| | | if (builder.longStopLossOrderIds != null) this.longStopLossOrderIds.addAll(builder.longStopLossOrderIds); |
| | | if (builder.shortStopLossOrderIds != null) this.shortStopLossOrderIds.addAll(builder.shortStopLossOrderIds); |
| | | } |
| | | |
| | | // ==================== 网格层级编号 ==================== |
| | |
| | | /** 设置下一个网格编号 */ |
| | | public void setDownId(Integer downId) { this.downId = downId; } |
| | | |
| | | // ==================== 多仓挂单订单 ID ==================== |
| | | // ==================== 多仓挂单订单 ID 列表 ==================== |
| | | |
| | | /** @return 多仓挂单订单 ID */ |
| | | public String getLongOrderId() { return longOrderId; } |
| | | /** 设置多仓挂单订单 ID */ |
| | | public void setLongOrderId(String longOrderId) { this.longOrderId = longOrderId; } |
| | | /** @return 多仓挂单订单 ID 列表 */ |
| | | public List<String> getLongOrderIds() { return longOrderIds; } |
| | | /** 添加多仓挂单订单 ID */ |
| | | public void addLongOrderId(String orderId) { if (orderId != null) longOrderIds.add(orderId); } |
| | | /** 移除多仓挂单订单 ID */ |
| | | public boolean removeLongOrderId(String orderId) { return longOrderIds.remove(orderId); } |
| | | /** 清空多仓挂单订单 ID */ |
| | | public void clearLongOrderIds() { longOrderIds.clear(); } |
| | | /** @return 是否有挂单 ID(列表非空) */ |
| | | public boolean hasLongOrderIds() { return !longOrderIds.isEmpty(); } |
| | | /** @deprecated 返回最后一个订单ID,用于单订单场景的兼容 */ |
| | | @Deprecated |
| | | public String getLongOrderId() { return longOrderIds.isEmpty() ? null : longOrderIds.get(longOrderIds.size() - 1); } |
| | | /** @deprecated 添加到列表,用于兼容旧调用 */ |
| | | @Deprecated |
| | | public void setLongOrderId(String orderId) { if (orderId != null) longOrderIds.add(orderId); } |
| | | |
| | | // ==================== 空仓挂单订单 ID ==================== |
| | | // ==================== 空仓挂单订单 ID 列表 ==================== |
| | | |
| | | /** @return 空仓挂单订单 ID */ |
| | | public String getShortOrderId() { return shortOrderId; } |
| | | /** 设置空仓挂单订单 ID */ |
| | | public void setShortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; } |
| | | /** @return 空仓挂单订单 ID 列表 */ |
| | | public List<String> getShortOrderIds() { return shortOrderIds; } |
| | | /** 添加空仓挂单订单 ID */ |
| | | public void addShortOrderId(String orderId) { if (orderId != null) shortOrderIds.add(orderId); } |
| | | /** 移除空仓挂单订单 ID */ |
| | | public boolean removeShortOrderId(String orderId) { return shortOrderIds.remove(orderId); } |
| | | /** 清空空仓挂单订单 ID */ |
| | | public void clearShortOrderIds() { shortOrderIds.clear(); } |
| | | /** @return 是否有挂单 ID(列表非空) */ |
| | | public boolean hasShortOrderIds() { return !shortOrderIds.isEmpty(); } |
| | | /** @deprecated 返回最后一个订单ID,用于单订单场景的兼容 */ |
| | | @Deprecated |
| | | public String getShortOrderId() { return shortOrderIds.isEmpty() ? null : shortOrderIds.get(shortOrderIds.size() - 1); } |
| | | /** @deprecated 添加到列表,用于兼容旧调用 */ |
| | | @Deprecated |
| | | public void setShortOrderId(String orderId) { if (orderId != null) shortOrderIds.add(orderId); } |
| | | |
| | | // ==================== 多仓止盈订单 ID ==================== |
| | | |
| | |
| | | public String getShortTakeProfitOrderId() { return shortTakeProfitOrderId; } |
| | | /** 设置空仓止盈订单 ID */ |
| | | public void setShortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; } |
| | | |
| | | // ==================== 多仓止损订单 ID ==================== |
| | | |
| | | // ==================== 多仓止损订单 ID 列表 ==================== |
| | | |
| | | /** @return 多仓止损订单 ID 列表 */ |
| | | public List<String> getLongStopLossOrderIds() { return longStopLossOrderIds; } |
| | | /** 添加一个多仓止损订单 ID */ |
| | | public void addLongStopLossOrderId(String orderId) { longStopLossOrderIds.add(orderId); } |
| | | /** 移除一个多仓止损订单 ID */ |
| | | public boolean removeLongStopLossOrderId(String orderId) { return longStopLossOrderIds.remove(orderId); } |
| | | /** 清空所有多仓止损订单 ID */ |
| | | public void clearLongStopLossOrderIds() { longStopLossOrderIds.clear(); } |
| | | /** @return 是否有止损单 */ |
| | | public boolean hasLongStopLossOrders() { return !longStopLossOrderIds.isEmpty(); } |
| | | |
| | | // ==================== 空仓止损订单 ID 列表 ==================== |
| | | |
| | | /** @return 空仓止损订单 ID 列表 */ |
| | | public List<String> getShortStopLossOrderIds() { return shortStopLossOrderIds; } |
| | | /** 添加一个空仓止损订单 ID */ |
| | | public void addShortStopLossOrderId(String orderId) { shortStopLossOrderIds.add(orderId); } |
| | | /** 移除一个空仓止损订单 ID */ |
| | | public boolean removeShortStopLossOrderId(String orderId) { return shortStopLossOrderIds.remove(orderId); } |
| | | /** 清空所有空仓止损订单 ID */ |
| | | public void clearShortStopLossOrderIds() { shortStopLossOrderIds.clear(); } |
| | | /** @return 是否有止损单 */ |
| | | public boolean hasShortStopLossOrders() { return !shortStopLossOrderIds.isEmpty(); } |
| | | |
| | | public static Builder builder() { |
| | | return new Builder(); |
| | |
| | | private Integer upId; |
| | | /** 下一个网格编号,默认 null(无下一级) */ |
| | | private Integer downId; |
| | | /** 多仓挂单订单 ID */ |
| | | private String longOrderId; |
| | | /** 空仓挂单订单 ID */ |
| | | private String shortOrderId; |
| | | /** 多仓挂单订单 ID 列表 */ |
| | | private List<String> longOrderIds; |
| | | /** 空仓挂单订单 ID 列表 */ |
| | | private List<String> shortOrderIds; |
| | | /** 多仓止盈订单 ID */ |
| | | private String longTakeProfitOrderId; |
| | | /** 空仓止盈订单 ID */ |
| | | private String shortTakeProfitOrderId; |
| | | /** 多仓止损订单 ID 列表 */ |
| | | private List<String> longStopLossOrderIds; |
| | | /** 空仓止损订单 ID 列表 */ |
| | | private List<String> shortStopLossOrderIds; |
| | | |
| | | /** 设置网格层级编号 */ |
| | | public Builder id(int id) { this.id = id; return this; } |
| | |
| | | public Builder upId(Integer upId) { this.upId = upId; return this; } |
| | | /** 设置下一个网格编号 */ |
| | | public Builder downId(Integer downId) { this.downId = downId; return this; } |
| | | /** 设置多仓挂单订单 ID */ |
| | | public Builder longOrderId(String longOrderId) { this.longOrderId = longOrderId; return this; } |
| | | /** 设置空仓挂单订单 ID */ |
| | | public Builder shortOrderId(String shortOrderId) { this.shortOrderId = shortOrderId; return this; } |
| | | /** 设置多仓挂单订单 ID 列表 */ |
| | | public Builder longOrderIds(List<String> longOrderIds) { this.longOrderIds = longOrderIds; return this; } |
| | | /** 设置空仓挂单订单 ID 列表 */ |
| | | public Builder shortOrderIds(List<String> shortOrderIds) { this.shortOrderIds = shortOrderIds; return this; } |
| | | /** 设置多仓止盈订单 ID */ |
| | | public Builder longTakeProfitOrderId(String longTakeProfitOrderId) { this.longTakeProfitOrderId = longTakeProfitOrderId; return this; } |
| | | /** 设置空仓止盈订单 ID */ |
| | | public Builder shortTakeProfitOrderId(String shortTakeProfitOrderId) { this.shortTakeProfitOrderId = shortTakeProfitOrderId; return this; } |
| | | /** 设置多仓止损订单 ID 列表 */ |
| | | public Builder longStopLossOrderIds(List<String> longStopLossOrderIds) { this.longStopLossOrderIds = longStopLossOrderIds; return this; } |
| | | /** 设置空仓止损订单 ID 列表 */ |
| | | public Builder shortStopLossOrderIds(List<String> shortStopLossOrderIds) { this.shortStopLossOrderIds = shortStopLossOrderIds; return this; } |
| | | |
| | | public GridElement build() { |
| | | return new GridElement(this); |