新版仿ok交易所-后端
1
dd
2026-05-30 030e1d50c1f643137220f1ecf1d90ce39174204a
trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
@@ -205,13 +205,13 @@
        if (!itemService.isContractTrading(item)) {
            throw new YamiShopBindException("未开放合约交易");
        }
        if (itemService.isSuspended(item.getSymbol())) {
        /*if (itemService.isSuspended(item.getSymbol())) {
            throw new YamiShopBindException("停牌禁止交易");
        }
        }*/
        List<ItemLeverageDTO> levers = itemLeverageService.findByItemId(item.getUuid());
        log.info("{}  --- order --- {}  --- {}", order.getSymbol(), item.getUuid(), levers.size());
        checkLever(order, levers);
        //checkLever(order, levers);
        order.setOrderNo(DateUtil.getToday("yyMMddHHmmss") + RandomUtil.getRandomNum(8));
@@ -237,10 +237,10 @@
        }
        Wallet wallet = this.walletService.findByUserId(order.getPartyId());
        BigDecimal amountBefore = wallet.getMoney();
        BigDecimal totalAmountCost = order.getDeposit().add(order.getFee());
        BigDecimal totalAmountCost = order.getDeposit().add(order.getFee() != null ? order.getFee() : BigDecimal.ZERO);
        BigDecimal available = getAvailableOpenMargin(order.getPartyId(), null);
        if (amountBefore.compareTo(totalAmountCost) < 0) {
        if (available.compareTo(totalAmountCost) < 0) {
            throw new YamiShopBindException("not sufficient funds");
        }
@@ -255,6 +255,48 @@
            );
        }
        save(order);
        // 市价单同步成交,避免异步撮合失败时长期挂单
        if (ContractApplyOrder.ORDER_PRICE_TYPE_OPPONENT.equals(order.getOrderPriceType())) {
            executeOpenImmediately(order);
        }
    }
    /**
     * 市价开仓立即撮合;失败则向上抛出,由事务回滚委托单。
     */
    private void executeOpenImmediately(ContractApplyOrder order) {
        List<Realtime> realtimes = dataService.realtime(order.getSymbol());
        if (CollectionUtil.isEmpty(realtimes)) {
            return;
        }
        contractOrderService.saveOpen(order, realtimes.get(0));
    }
    /**
     * 可用于新开仓的余额(双向持仓下多空各自占用保证金,需扣除未成交市价委托预留额)。
     *
     * @param excludeOrderNo 正在成交的委托单号,不计入预留
     */
    public BigDecimal getAvailableOpenMargin(String partyId, String excludeOrderNo) {
        Wallet wallet = walletService.findByUserId(partyId);
        if (wallet == null || wallet.getMoney() == null) {
            return BigDecimal.ZERO;
        }
        BigDecimal available = wallet.getMoney();
        List<ContractApplyOrder> pendingOpens = findSubmitted(partyId, null, ContractApplyOrder.OFFSET_OPEN, null);
        for (ContractApplyOrder pending : pendingOpens) {
            if (excludeOrderNo != null && excludeOrderNo.equals(pending.getOrderNo())) {
                continue;
            }
            if (!ContractApplyOrder.ORDER_PRICE_TYPE_OPPONENT.equals(pending.getOrderPriceType())) {
                continue;
            }
            BigDecimal deposit = pending.getDeposit() != null ? pending.getDeposit() : BigDecimal.ZERO;
            BigDecimal fee = pending.getFee() != null ? pending.getFee() : BigDecimal.ZERO;
            available = available.subtract(deposit).subtract(fee);
        }
        return available.max(BigDecimal.ZERO);
    }
    /**