Administrator
2026-09-20 aedc84e8b7744796c9f5a6132e0b1227d57fbd45
```
fix(gateApi): 修复网格交易队列生成的并发安全问题

- 在重置基础交易参数时设置为null,确保状态一致性
- 在长短期订单打开回调中调用tryGenerateQueues方法,保证时机正确
- 将tryGenerateQueues方法改为同步方法,防止多线程并发执行
- 添加幂等性保护,只有在OPENING状态下才执行队列生成
- 增加参数就绪检查,确保订单ID获取完成后再生成队列
```
1 files modified
22 ■■■■■ changed files
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java 22 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/gateApi/GateGridTradeService.java
@@ -354,6 +354,8 @@
        shortPositionSize = BigDecimal.ZERO;
        baseLongOpened = false;
        baseShortOpened = false;
        config.setBaseLongTraderParam(null);
        config.setBaseShortTraderParam(null);
        longActive = false;
        shortActive = false;
        accumulatedLongLossCount = 0;
@@ -453,12 +455,14 @@
                        .entryOrderId(orderId)
                        .build();
                config.setBaseLongTraderParam(baseLongTp);
                tryGenerateQueues();
            }, null);
            executor.openShort(negate(size), (orderId) -> {
                TraderParam baseShortTp = TraderParam.builder()
                        .entryOrderId(orderId)
                        .build();
                config.setBaseShortTraderParam(baseShortTp);
                tryGenerateQueues();
            }, null);
            return;
        }
@@ -872,17 +876,27 @@
     *   <li>状态切换为 ACTIVE</li>
     * </ol>
     */
    private void tryGenerateQueues() {
        if (baseLongOpened && baseShortOpened) {
    private synchronized void tryGenerateQueues() {
        // 幂等保护:生成队列后 state 切换为 ACTIVE,避免多线程重复执行
        if (state != StrategyState.OPENING) {
            return;
        }
        TraderParam baseLongTraderParam = config.getBaseLongTraderParam();
        TraderParam baseShortTraderParam = config.getBaseShortTraderParam();
        // 需同时满足:多空基底均已成交,且两个下单参数(orderId)均已通过下单成功回调拿到。
        // IOC 市价单成交后 WS 持仓推送可能先于 REST 下单响应返回,必须等参数就绪再生成队列。
        if (!(baseLongOpened && baseShortOpened)
                || baseLongTraderParam == null || baseShortTraderParam == null) {
            return;
        }
        {
            generateShortQueue();
            generateLongQueue();
            updateGridElements();
            GridElement baseGridElement = GridElement.findById(0);
            TraderParam baseLongTraderParam = config.getBaseLongTraderParam();
            baseGridElement.setLongOrderId(baseLongTraderParam.getEntryOrderId());
            baseGridElement.setHasLongOrder(true);
            TraderParam baseShortTraderParam = config.getBaseShortTraderParam();
            baseGridElement.setShortOrderId(baseShortTraderParam.getEntryOrderId());
            baseGridElement.setHasShortOrder(true);