From 98a5e458479e7f0034fda19e12cf7c04675f88c8 Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Fri, 22 May 2026 10:25:37 +0800
Subject: [PATCH] 1

---
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java |  335 ++++++++++++++++++++++++++-----------------------------
 1 files changed, 160 insertions(+), 175 deletions(-)

diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
index 2d1416c..3d3ccdc 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java
@@ -1,15 +1,12 @@
 package com.yami.trading.service.contract;
 
-import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.yami.trading.bean.contract.domain.ContractOrder;
+import com.yami.trading.bean.contract.domain.ContractOrderProfit;
 import com.yami.trading.bean.data.domain.Realtime;
 import com.yami.trading.bean.item.domain.Item;
 import com.yami.trading.bean.model.Wallet;
-import com.yami.trading.common.util.ThreadUtils;
-import com.yami.trading.service.StrongLevelCalculationService;
 import com.yami.trading.service.WalletService;
 import com.yami.trading.service.data.DataService;
-import com.yami.trading.service.impl.StrongLevelCalculationServiceImpl;
 import com.yami.trading.service.item.ItemService;
 import com.yami.trading.service.syspara.SysparaService;
 import lombok.extern.slf4j.Slf4j;
@@ -20,8 +17,8 @@
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.Date;
 import java.util.List;
-import java.util.Map;
 
 @Slf4j
 @Service
@@ -45,9 +42,6 @@
     @Autowired
     private WalletService walletService;
 
-    @Autowired
-    private StrongLevelCalculationService strongLevelCalculationService;
-
     private SysparaService sysparaService;
 
     public void saveCalculation(String order_no, List<ContractOrder> partyContractOrders) {
@@ -67,6 +61,7 @@
             Realtime realtime = list.get(0);
 
             BigDecimal close = realtime.getClose();
+            settle(order, "watch", close, partyContractOrders);
 
             BigDecimal add = order.getTradeAvgPrice().add(order.getPips());
             BigDecimal subtract = order.getTradeAvgPrice().subtract(order.getPips());
@@ -101,101 +96,14 @@
     }
 
     /**
-     * 盈亏计算   收益=(平仓均价-开仓均价)*面值*张数
-     *
-     * USDT保证金合约做多:收益=(平仓均价-开仓均价)*面值*张数
-     * USDT保证金合约做空:收益=(开仓均价-平仓均价)*面值*张数
-     * 以BTC为例,BTC一张合约面值为0.01BTC,在价格19000的时候,开了10张多单。当价格涨到20000的时候,小明的收益=(20000-19000)*0.01*10=100USDT
-     * 币本位合约:
-     * 做多:收益=面值*张数/开仓价-面值*张数/平仓价
-     * 做空:收益=面值*张数/平仓价-面值*张数/开仓价
-     * 以BTC为例,BTC一张合约面值为100美元,小明在价格20000的时候,开了5张空单。当价格下跌到19000的时候,小明的收益=100*5/19000-100*5/20000=0.
+     * 盈亏计算
      *
      * @param profit_loss  profit 盈 loss亏
      * @param currentPrice 当前点位
      */
     public void settle(ContractOrder order, String profit_loss, BigDecimal currentPrice, List<ContractOrder> partyContractOrders) {
 
-        Item item = itemService.findBySymbol(order.getSymbol());
-
-
-        if(null != order.getProfitLossRatio() && order.getProfitLossRatio() > 0){//根据后台设置的盈亏比来
-            order.setProfit(order.getDepositOpen().multiply(new BigDecimal((order.getProfitLossRatio()/100))).setScale(2, RoundingMode.DOWN));
-        }else{
-            /*
-             * 根据偏 差点数和手数算出盈亏金额
-             */
-            /**
-             * 偏差点位
-             */
-            BigDecimal point = currentPrice.subtract(order.getTradeAvgPrice());
-            BigDecimal amount = point.multiply(new BigDecimal("0.01")).multiply(order.getVolumeOpen()).setScale(4, BigDecimal.ROUND_DOWN);
-            if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
-                order.setProfit(amount);
-            } else{
-                order.setProfit(amount.negate());
-            }
-        }
-
-        double faceValue = 0.01; // 合约面值(固定面值不能调整)
-        double maintenanceMarginRate = 0.004; // 维持保证金率(固定不变)
-
-
-        /**
-         * 全仓收益加入保证金计算
-         */
-        BigDecimal earnings;
-
-        if (order.getLocationType() == 1) {
-            earnings = BigDecimal.ZERO;
-
-            // 统计非当前订单的其他收益
-            /*List<ContractOrder> list = contractOrderService.list(new LambdaQueryWrapper<>(ContractOrder.class)
-                    .eq(ContractOrder::getState, ContractOrder.STATE_SUBMITTED)
-                    .eq(ContractOrder::getPartyId, order.getPartyId())
-                    .ne(ContractOrder::getOrderNo, order.getOrderNo())
-            );
-
-            // 提前计算 currentPrice 与 order.getTradeAvgPrice() 的差值,避免重复计算
-            BigDecimal priceDifference = currentPrice.subtract(order.getTradeAvgPrice());
-
-            // 计算所有订单的收益
-            for (ContractOrder contractOrder : list) {
-                BigDecimal profit = priceDifference
-                        .multiply(new BigDecimal("0.01"))
-                        .multiply(contractOrder.getVolumeOpen())
-                        .setScale(4, RoundingMode.DOWN);
-
-                earnings = earnings.add(profit);  // 累加收益
-            }*/
-
-            // 获取当前账户余额并加到收益中
-            //Map<String, Object> moneyAll = walletService.getMoneyAll(order.getPartyId());
-
-            Wallet wallet = walletService.saveWalletByPartyId(order.getPartyId());
-            earnings = earnings.add(wallet.getMoney());
-            earnings = earnings.add(order.getDepositOpen());
-        } else {
-            // 如果不符合条件,直接使用 order.getDepositOpen() 作为收益
-            earnings = order.getDepositOpen().add(order.getAddDepositOpen());
-        }
-
-        if(ContractOrder.DIRECTION_BUY.equals(order.getDirection())){
-            double forceClosePrice = strongLevelCalculationService.calculateLiquidationPrice(earnings.doubleValue(),
-                    faceValue, order.getVolumeOpen().doubleValue(), order.getTradeAvgPrice().doubleValue()
-                    , maintenanceMarginRate, item.getUnitFee().doubleValue());
-            order.setForceClosePrice(BigDecimal.valueOf(forceClosePrice).toString());
-        }else{
-            double forceClosePrice = strongLevelCalculationService.calculateEmptyLiquidationPrice(earnings.doubleValue(),
-                    faceValue, order.getVolumeOpen().doubleValue(), order.getTradeAvgPrice().doubleValue()
-                    , maintenanceMarginRate, item.getUnitFee().doubleValue());
-            order.setForceClosePrice(BigDecimal.valueOf(forceClosePrice).toString());
-        }
-        /**
-         * 多次平仓价格不对,后续修
-         */
-        order.setCloseAvgPrice(currentPrice);
-        this.contractOrderService.updateByIdBuffer(order);
+        applyMarkPriceToOrder(order, currentPrice);
 
         /**
          * 止盈价
@@ -206,7 +114,7 @@
              * 买涨
              */
             if (currentPrice.compareTo(profitStop) >= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),null);
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         } else if (profitStop != null && profitStop.compareTo(BigDecimal.ZERO) > 0
@@ -215,7 +123,7 @@
              * 买跌
              */
             if (currentPrice.compareTo(profitStop) <= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),null);
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         }
@@ -230,7 +138,7 @@
              * 买涨
              */
             if (currentPrice.compareTo(loss_stop) <= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),null);
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
 
             }
@@ -240,88 +148,157 @@
              */
 
             if (currentPrice.compareTo(loss_stop) >= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),null);
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         }
-        /**
-         * 强平计算
-         */
-        //重新计算强平
-        BigDecimal forceClosePrice = new BigDecimal(order.getForceClosePrice());
-        //达到强平价
-        if ((ContractOrder.DIRECTION_BUY.equals(order.getDirection()) && currentPrice.compareTo(new BigDecimal(order.getForceClosePrice())) <= 0)
-                || (ContractOrder.DIRECTION_SELL.equals(order.getDirection()) && currentPrice.compareTo(new BigDecimal(order.getForceClosePrice())) >= 0)) {
-            BigDecimal point = forceClosePrice.subtract(order.getTradeAvgPrice());
-            BigDecimal amount = point.multiply(new BigDecimal("0.01")).multiply(order.getVolumeOpen()).setScale(4, BigDecimal.ROUND_DOWN);
-            if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
-                order.setProfit(amount);
-            } else{
-                order.setProfit(amount.negate());
-            }
-            //强平利润固定-100%
-            order.setProfit(order.getDepositOpen().add(order.getAddDepositOpen()).negate());
-            //全仓强平利润+账户余额
-            if (order.getLocationType() == 1) {
-                Wallet wallet = this.walletService.findByUserId(order.getPartyId());
-                order.setProfit(order.getProfit().subtract(wallet.getMoney()));
-            }
-        }
+        ContractOrderProfit cp = contractOrderService.getCacheProfit(order.getUuid());
+        BigDecimal profit1 = cp != null ? cp.getProfit() : defaultZero(order.getProfit());
+        order.setForceClosePrice(calculateForceClosePriceForOrder(order));
         this.contractOrderService.updateByIdBuffer(order);
-        //判断是全仓还是逐仓
-        if (order.getLocationType() == 1) {
-//            /**
-//             * 收益
-//             */
-//            BigDecimal profit = BigDecimal.ZERO;
-//
-//            List<ContractOrder> list = partyContractOrders;
-//            for (int i = 0; i < list.size(); i++) {
-//                ContractOrder close_line = list.get(i);
-//                profit = profit.add(close_line.getProfit()).add(close_line.getDeposit());
-//            }
-
-
-//            Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString());
-            //this.contractOrderService.updateByIdBuffer(order);
-
-//            if (profit.add(wallet.getMoney()).compareTo(BigDecimal.ZERO) <= 0) {
-            //判断买涨还是买跌"buy":买(多) "sell":卖(空)
-            if(order.getDirection().equals("buy")){
-                if (currentPrice.compareTo(new BigDecimal(order.getForceClosePrice())) <= 0) {//达到强平价
-                    /**
-                     * 触发全仓强平
-                     */
-                    log.info("------------------currentPrice-------------:"+currentPrice);
-                    log.info("------------------order.getForceClosePrice()-------------"+order.getForceClosePrice());
-                    log.info("------------------开多强平-------------");
-                    this.contractOrderService.allClose(order.getPartyId());
+        if (order_close_line_type == 1) {
+            Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString());
+            List<ContractOrder> list = contractOrderService.findSubmitted(order.getPartyId(), null, null, null, null, null);
+            BigDecimal totalEquity = defaultZero(wallet.getMoney());
+            for (ContractOrder contractOrder : list) {
+                if (ContractOrder.STATE_SUBMITTED.equals(contractOrder.getState())) {
+                    contractOrderService.wrapProfit(contractOrder);
                 }
-            }else{
-                if (currentPrice.compareTo(new BigDecimal(order.getForceClosePrice()))>= 0) {//达到强平价
-                    /**
-                     * 触发全仓强平
-                     */
-                    log.info("------------------currentPrice-------------:"+currentPrice);
-                    log.info("------------------order.getForceClosePrice()-------------"+order.getForceClosePrice());
-                    log.info("------------------开空强平-------------");
-                    this.contractOrderService.allClose(order.getPartyId());
+                totalEquity = totalEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
+            }
 
-                }
+            if (totalEquity.compareTo(BigDecimal.ZERO) <= 0) {
+                /**
+                 * 触发全仓强平
+                 */
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), "强平");
+
             }
         } else {
-            if(order.getDirection().equals("buy")){
-                if (currentPrice.compareTo(new BigDecimal(order.getForceClosePrice())) <= 0) {//达到强平价
-                    this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),"强平");
-                }
-            }else{
-                if (currentPrice.compareTo(new BigDecimal(order.getForceClosePrice())) >= 0) {//达到强平价
-                    this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(),"强平");
-                }
+            if (profit1.compareTo(BigDecimal.ZERO) >= 0 || profit1.abs().compareTo(new BigDecimal("0.000001")) < 0) {
+                return;
             }
+            BigDecimal divide = order.getDeposit().divide(profit1.abs(), 10, RoundingMode.HALF_UP);
+            if (divide.compareTo(order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP)) <= 0) {
+                /**
+                 * 低于系统默认平仓线,进行强平
+                 */
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), "强平");
+            }
+        }
+    }
 
+    @Override
+    public String calculateForceClosePriceForOrder(ContractOrder order) {
+        if (order == null || defaultZero(order.getVolume()).compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO.toPlainString();
+        }
+        BigDecimal forceClose;
+        if (order_close_line_type == 1) {
+            Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString());
+            forceClose = calculateType1ForceClosePrice(order, wallet);
+        } else {
+            forceClose = calculateType2ForceClosePrice(order);
+        }
+        if (forceClose.compareTo(BigDecimal.ZERO) < 0) {
+            forceClose = BigDecimal.ZERO;
+        }
+        Integer decimal = itemService.getDecimal(order.getSymbol());
+        return forceClose.setScale(decimal, RoundingMode.HALF_UP).toPlainString();
+    }
+
+    private BigDecimal defaultZero(BigDecimal value) {
+        return value == null ? BigDecimal.ZERO : value;
+    }
+
+    /**
+     * 合约张数对应标的数量系数(每张面值,与 countSheets 一致,默认 0.01)
+     */
+    private BigDecimal getContractFaceValue(ContractOrder order) {
+        Item item = itemService.findBySymbol(order.getSymbol());
+        if (item != null && item.getFaceValue() > 0) {
+            return BigDecimal.valueOf(item.getFaceValue());
+        }
+        return new BigDecimal("0.01");
+    }
+
+    /**
+     * 每张张数对应的价格敏感度:盈亏/强平 = 价差 × volume × faceValue
+     */
+    private BigDecimal getVolumePriceFactor(ContractOrder order) {
+        return defaultZero(order.getVolume()).multiply(getContractFaceValue(order));
+    }
+
+    private BigDecimal calculateType1ForceClosePrice(ContractOrder order, Wallet wallet) {
+        BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice());
+        BigDecimal volumeFactor = getVolumePriceFactor(order);
+        if (volumeFactor.compareTo(BigDecimal.ZERO) <= 0 || tradeAvgPrice.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
         }
 
+        List<ContractOrder> list = contractOrderService.findSubmitted(order.getPartyId(), null, null, null, null, null);
+        BigDecimal otherEquity = BigDecimal.ZERO;
+        for (ContractOrder contractOrder : list) {
+            if (ContractOrder.STATE_SUBMITTED.equals(contractOrder.getState())) {
+                contractOrderService.wrapProfit(contractOrder);
+            }
+            if (order.getUuid().equals(contractOrder.getUuid())) {
+                continue;
+            }
+            otherEquity = otherEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
+        }
+
+        BigDecimal baseEquity = defaultZero(wallet.getMoney())
+                .add(otherEquity)
+                .add(defaultZero(order.getDeposit()));
+        BigDecimal priceOffset = baseEquity.divide(volumeFactor, 10, RoundingMode.HALF_UP);
+        if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) {
+            return tradeAvgPrice.subtract(priceOffset);
+        }
+        return tradeAvgPrice.add(priceOffset);
+    }
+
+    private BigDecimal calculateType2ForceClosePrice(ContractOrder order) {
+        BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice());
+        BigDecimal volumeFactor = getVolumePriceFactor(order);
+        if (volumeFactor.compareTo(BigDecimal.ZERO) <= 0 || tradeAvgPrice.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        BigDecimal thresholdRatio = order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP);
+        if (thresholdRatio.compareTo(BigDecimal.ZERO) <= 0) {
+            return tradeAvgPrice;
+        }
+        BigDecimal availableDeposit = defaultZero(order.getDeposit());
+        if (availableDeposit.compareTo(BigDecimal.ZERO) <= 0) {
+            return tradeAvgPrice;
+        }
+        BigDecimal requiredLoss = availableDeposit.divide(thresholdRatio, 10, RoundingMode.HALF_UP);
+        BigDecimal priceOffset = requiredLoss.divide(volumeFactor, 10, RoundingMode.HALF_UP);
+        if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) {
+            return tradeAvgPrice.subtract(priceOffset);
+        }
+        return tradeAvgPrice.add(priceOffset);
+    }
+
+    private void applyMarkPriceToOrder(ContractOrder order, BigDecimal currentPrice) {
+        BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice());
+        if (tradeAvgPrice.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        BigDecimal volumeFactor = getVolumePriceFactor(order);
+        if (volumeFactor.compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        // 与平仓结算一致:盈亏 = (现价 - 开仓价) × 张数 × 面值
+        BigDecimal point = currentPrice.subtract(tradeAvgPrice);
+        BigDecimal priceProfit = point.multiply(volumeFactor).setScale(6, RoundingMode.DOWN);
+        if (!ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
+            priceProfit = priceProfit.negate();
+        }
+        BigDecimal fundingPnl = contractOrderService.calculateAccruedFundingPnl(order, currentPrice, new Date());
+        order.setProfit(priceProfit.add(fundingPnl));
+        order.setCloseAvgPrice(currentPrice);
+        this.contractOrderService.updateByIdBuffer(order);
     }
 
     public void setDataService(DataService dataService) {
@@ -348,10 +325,18 @@
         this.order_close_line_type = order_close_line_type;
     }
 
-    public static void main(String[] args) {
-        StrongLevelCalculationService strongLevelCalculationService = new StrongLevelCalculationServiceImpl();
-        double forceClosePrice = strongLevelCalculationService.calculateLiquidationPrice(100,
-                0.01, 67704.80, 1.477
-                , 0.004, 0.0005);
+    @Override
+    public void refreshMarkPriceProfit(ContractOrder order) {
+        if (order == null || !ContractOrder.STATE_SUBMITTED.equals(order.getState())) {
+            return;
+        }
+        if (defaultZero(order.getVolume()).compareTo(BigDecimal.ZERO) <= 0) {
+            return;
+        }
+        List<Realtime> list = this.dataService.realtime(order.getSymbol());
+        if (list.isEmpty()) {
+            return;
+        }
+        applyMarkPriceToOrder(order, list.get(0).getClose());
     }
 }

--
Gitblit v1.9.3