From dc6abd25de0fc12e7a9de54f628f970c8fdc5910 Mon Sep 17 00:00:00 2001
From: zyy <zyy@email.com>
Date: Fri, 22 May 2026 16:57:16 +0800
Subject: [PATCH] 理财

---
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java |  247 +++++++++++++++++++++++++++++++------------------
 1 files changed, 155 insertions(+), 92 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 54a2976..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,9 +1,10 @@
 package com.yami.trading.service.contract;
 
 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.WalletService;
 import com.yami.trading.service.data.DataService;
 import com.yami.trading.service.item.ItemService;
@@ -16,6 +17,7 @@
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.util.Date;
 import java.util.List;
 
 @Slf4j
@@ -39,6 +41,7 @@
     private DataService dataService;
     @Autowired
     private WalletService walletService;
+
     private SysparaService sysparaService;
 
     public void saveCalculation(String order_no, List<ContractOrder> partyContractOrders) {
@@ -58,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());
@@ -98,28 +102,8 @@
      * @param currentPrice 当前点位
      */
     public void settle(ContractOrder order, String profit_loss, BigDecimal currentPrice, List<ContractOrder> partyContractOrders) {
-        /**
-         * 偏差点位
-         */
-        BigDecimal point = currentPrice.subtract(order.getTradeAvgPrice()).abs().divide(order.getPips(), 10, RoundingMode.HALF_UP);
-        /*
-         * 根据偏 差点数和手数算出盈亏金额
-         */
-        BigDecimal amount = order.getPipsAmount().multiply(point).multiply(order.getVolume());
 
-        if ("profit".equals(profit_loss)) {
-            /**
-             * 盈 正数
-             */
-            order.setProfit(amount);
-        } else if ("loss".equals(profit_loss)) {
-            order.setProfit(amount.negate());
-        }
-        /**
-         * 多次平仓价格不对,后续修
-         */
-        order.setCloseAvgPrice(currentPrice);
-        this.contractOrderService.updateByIdBuffer(order);
+        applyMarkPriceToOrder(order, currentPrice);
 
         /**
          * 止盈价
@@ -130,7 +114,7 @@
              * 买涨
              */
             if (currentPrice.compareTo(profitStop) >= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo());
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         } else if (profitStop != null && profitStop.compareTo(BigDecimal.ZERO) > 0
@@ -139,7 +123,7 @@
              * 买跌
              */
             if (currentPrice.compareTo(profitStop) <= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo());
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         }
@@ -154,7 +138,7 @@
              * 买涨
              */
             if (currentPrice.compareTo(loss_stop) <= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo());
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
 
             }
@@ -164,93 +148,158 @@
              */
 
             if (currentPrice.compareTo(loss_stop) >= 0) {
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo());
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), null);
                 return;
             }
         }
+        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_close_line_type == 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());
-            // 计算所有除自己以外的profit
-            BigDecimal profitExptThis = profit.subtract(order.getProfit()).subtract(order.getDeposit());
-            /**
-             * profitAll+wallet<=0
-             * profitAll<=wallet 强平
-             * p1 +E (p2~pn) <=wallet
-             * (currentPrice-tradavg)*pipAmount*volume/pips + depost1 <=wallet-E(p2~pn)
-             */
-            BigDecimal left = wallet.getMoney().negate().subtract(profitExptThis).subtract(order.getDeposit());
-            BigDecimal overLine = (left.multiply(order.getPips()).divide(order.getPipsAmount(), 10, RoundingMode.HALF_UP)
-                    .divide(order.getVolume(), 10, RoundingMode.HALF_UP));
-            Integer decimal = itemService.getDecimal(order.getSymbol());
-            BigDecimal forceClose = BigDecimal.ZERO;
-            // 买多,从买价跌多少
-            if (order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)) {
-                forceClose = order.getTradeAvgPrice().add(overLine).setScale(decimal, RoundingMode.HALF_UP);
-                //买跌,涨到多少
-            } else {
-                forceClose = order.getTradeAvgPrice().subtract(overLine).setScale(decimal, RoundingMode.HALF_UP);
+            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);
+                }
+                totalEquity = totalEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
             }
-            if (forceClose.compareTo(BigDecimal.ZERO) < 0) {
-                forceClose = BigDecimal.ZERO;
-            }
-            order.setForceClosePrice(forceClose.toPlainString());
-            this.contractOrderService.updateByIdBuffer(order);
 
-            if (profit.add(wallet.getMoney()).compareTo(BigDecimal.ZERO) <= 0) {
+            if (totalEquity.compareTo(BigDecimal.ZERO) <= 0) {
                 /**
                  * 触发全仓强平
                  */
-                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo());
-                ThreadUtils.sleep(100);
-                for (int i = 0; i < list.size(); i++) {
-                    ContractOrder close_line = list.get(i);
-                    if (!order.getOrderNo().equals(close_line.getOrderNo())) {
-                        try {
-                            if (ContractLock.add(close_line.getOrderNo())) {
-                                this.contractOrderService.saveClose(close_line.getPartyId().toString(),
-                                        close_line.getOrderNo());
-                            }
-                        } catch (Exception e) {
-                            log.error("error:", e);
-                        } finally {
-                            ContractLock.remove(close_line.getOrderNo());
-                        }
-
-                    }
-                }
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), "强平");
 
             }
         } else {
-            BigDecimal divide = order.getDeposit().divide(order.getProfit().abs(), 10, RoundingMode.HALF_UP);
-            if (order.getProfit().compareTo(BigDecimal.ZERO) < 0 && divide.compareTo(order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP)) <= 0) {
+            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());
-                return;
+                this.contractOrderService.saveClose(order.getPartyId().toString(), order.getOrderNo(), "强平");
             }
         }
-
     }
 
-//	@Override
-//	public void afterPropertiesSet() throws Exception {
-//		order_close_line = this.sysparaService.find("order_close_line").getDouble();
-//		order_close_line_type = this.sysparaService.find("order_close_line_type").getInteger();
-//
-//	}
+    @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) {
         this.dataService = dataService;
@@ -276,4 +325,18 @@
         this.order_close_line_type = order_close_line_type;
     }
 
+    @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