From 5e57de9b12ee136e45ce5754c7fe2e7eb12af05a Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Fri, 12 Jun 2026 18:35:45 +0800
Subject: [PATCH] 1

---
 trading-order-service/src/main/java/com/yami/trading/service/future/FuturesOrderService.java |  216 +++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 181 insertions(+), 35 deletions(-)

diff --git a/trading-order-service/src/main/java/com/yami/trading/service/future/FuturesOrderService.java b/trading-order-service/src/main/java/com/yami/trading/service/future/FuturesOrderService.java
index f1c05e2..c96ed88 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/future/FuturesOrderService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/future/FuturesOrderService.java
@@ -208,6 +208,87 @@
      * @param operaName
      * @return
      */
+    public String saveOrderManualProfitPercent(String orderNo, Double manualProfitPercent, String profitLoss, String operaName) {
+        if (manualProfitPercent == null) {
+            return "盈亏百分比不能为空";
+        }
+        double absPercent = Math.abs(manualProfitPercent);
+        if (absPercent <= 0) {
+            return "盈亏百分比必须大于0";
+        }
+        double signedPercent;
+        String resolvedProfitLoss;
+        if (StrUtil.isNotBlank(profitLoss)) {
+            resolvedProfitLoss = profitLoss.trim().toLowerCase();
+            if ("loss".equals(resolvedProfitLoss)) {
+                signedPercent = -absPercent;
+                resolvedProfitLoss = "loss";
+            } else if ("profit".equals(resolvedProfitLoss)) {
+                signedPercent = absPercent;
+                resolvedProfitLoss = "profit";
+            } else {
+                return "场控方向无效";
+            }
+        } else {
+            signedPercent = manualProfitPercent;
+            resolvedProfitLoss = signedPercent >= 0 ? "profit" : "loss";
+        }
+        String message = "";
+        boolean lock = false;
+        while (true) {
+            try {
+                if (!FuturesLock.add(orderNo)) {
+                    continue;
+                }
+                lock = true;
+                FuturesOrder futuresOrder = (FuturesOrder) RedisUtil.get(FuturesRedisKeys.FUTURES_SUBMITTED_ORDERNO + orderNo);
+                if (futuresOrder == null) {
+                    futuresOrder = cache.get(orderNo);
+                }
+                if (futuresOrder == null || FuturesOrder.STATE_CREATED.equals(futuresOrder.getState())) {
+                    message = "订单已结算或不存在";
+                    break;
+                }
+                Double oldPercent = futuresOrder.getManualProfitPercent();
+                String oldProfitLoss = futuresOrder.getProfitLoss();
+                futuresOrder.setProfitLoss(resolvedProfitLoss);
+                futuresOrder.setManualProfitPercent(signedPercent);
+                applyManualProfitPercentToOrder(futuresOrder);
+                Double close = futuresOrder.getCloseAvgPrice();
+                if (close == null) {
+                    close = futuresOrder.getTradeAvgPrice();
+                }
+                refreshCache(futuresOrder, close);
+                RedisUtil.set(FuturesRedisKeys.FUTURES_SUBMITTED_ORDERNO + futuresOrder.getOrderNo(), futuresOrder);
+                cache.put(futuresOrder.getOrderNo(), futuresOrder);
+                updateById(futuresOrder);
+
+                User party = userService.getById(futuresOrder.getPartyId());
+                Log log = new Log();
+                log.setCategory(Constants.LOG_CATEGORY_OPERATION);
+                log.setOperator(operaName);
+                log.setUsername(party.getUserName());
+                log.setUserId(party.getUserId());
+                log.setCreateTime(new Date());
+                log.setLog("设定交割订单场控与盈亏比例。订单号[" + futuresOrder.getOrderNo() + "],场控["
+                        + Constants.PROFIT_LOSS_TYPE.get(oldProfitLoss) + "→"
+                        + Constants.PROFIT_LOSS_TYPE.get(resolvedProfitLoss) + "],比例["
+                        + oldPercent + "→" + signedPercent + "%].");
+                this.logService.save(log);
+                ThreadUtils.sleep(100);
+            } catch (Throwable e) {
+                log.error("error:", e);
+                message = "修改错误";
+            } finally {
+                if (lock) {
+                    FuturesLock.remove(orderNo);
+                    break;
+                }
+            }
+        }
+        return message;
+    }
+
     public String saveOrderPorfitOrLoss(String orderNo, String porfitOrLoss, String operaName) {
         String message = "";
         boolean lock = false;
@@ -229,6 +310,7 @@
                 Map<String, Double> futuresAssetsOld = this.walletService.getMoneyFuturesByOrder(futuresOrder);
 
                 String oldProfitLoss = futuresOrder.getProfitLoss();
+                futuresOrder.setManualProfitPercent(null);
                 futuresOrder.setProfitLoss(porfitOrLoss);
 
                 RedisUtil.set(FuturesRedisKeys.FUTURES_SUBMITTED_ORDERNO + futuresOrder.getOrderNo(), futuresOrder);
@@ -330,7 +412,7 @@
             realtime = realtime_list.get(0);
         }
         if (null == realtime) {
-            throw new BusinessException(1, "请稍后再试");
+            throw new BusinessException(1, "行情获取失败,请稍后再试");
         }
 
         Double volume = futuresOrder.getVolume();
@@ -454,41 +536,45 @@
         order.setRemainTime(fomatTime(remain_time));
         order.setCloseAvgPrice(close);
 
-        double futures_loss_part = Double.valueOf(this.sysparaService.find("futures_loss_part").getSvalue());
-
-        double closeAvgPrice = order.getCloseAvgPrice().doubleValue();
-        double tradeAvgPrice = order.getTradeAvgPrice().doubleValue();
-        if (FuturesOrder.DIRECTION_BUY.equals(order.getDirection())) {
-            /*
-             * 0 买涨
-             */
-            if (closeAvgPrice >= tradeAvgPrice) {
-                DecimalFormat df = new DecimalFormat("#.##");
-                order.setProfit(Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio()))));
-            }
-
-            if (closeAvgPrice <= tradeAvgPrice) {
-                if (futures_loss_part == 2) {
-                    DecimalFormat df = new DecimalFormat("#.##");
-                    order.setProfit(Arith.sub(0, Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio())))));
-                } else {
-                    order.setProfit(Arith.sub(0, order.getVolume()));
-                }
-            }
+        if (order.getManualProfitPercent() != null) {
+            applyManualProfitPercentToOrder(order);
         } else {
-            /*
-             * 1 买跌
-             */
-            if (closeAvgPrice <= tradeAvgPrice) {
-                DecimalFormat df = new DecimalFormat("#.##");
-                order.setProfit(Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio()))));
-            }
-            if (closeAvgPrice >= tradeAvgPrice) {
-                if (futures_loss_part == 2) {
+            double futures_loss_part = Double.valueOf(this.sysparaService.find("futures_loss_part").getSvalue());
+
+            double closeAvgPrice = order.getCloseAvgPrice().doubleValue();
+            double tradeAvgPrice = order.getTradeAvgPrice().doubleValue();
+            if (FuturesOrder.DIRECTION_BUY.equals(order.getDirection())) {
+                /*
+                 * 0 买涨
+                 */
+                if (closeAvgPrice >= tradeAvgPrice) {
                     DecimalFormat df = new DecimalFormat("#.##");
-                    order.setProfit(Arith.sub(0, Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio())))));
-                } else {
-                    order.setProfit(Arith.sub(0, order.getVolume()));
+                    order.setProfit(Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio()))));
+                }
+
+                if (closeAvgPrice <= tradeAvgPrice) {
+                    if (futures_loss_part == 2) {
+                        DecimalFormat df = new DecimalFormat("#.##");
+                        order.setProfit(Arith.sub(0, Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio())))));
+                    } else {
+                        order.setProfit(Arith.sub(0, order.getVolume()));
+                    }
+                }
+            } else {
+                /*
+                 * 1 买跌
+                 */
+                if (closeAvgPrice <= tradeAvgPrice) {
+                    DecimalFormat df = new DecimalFormat("#.##");
+                    order.setProfit(Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio()))));
+                }
+                if (closeAvgPrice >= tradeAvgPrice) {
+                    if (futures_loss_part == 2) {
+                        DecimalFormat df = new DecimalFormat("#.##");
+                        order.setProfit(Arith.sub(0, Double.valueOf(df.format(Arith.mul(order.getVolume(), order.getProfitRatio())))));
+                    } else {
+                        order.setProfit(Arith.sub(0, order.getVolume()));
+                    }
                 }
             }
         }
@@ -642,6 +728,11 @@
         order.setCloseTime(System.currentTimeMillis() / 1000);
         order.setState(FuturesOrder.STATE_CREATED);
 
+        if (order.getManualProfitPercent() != null) {
+            settleByManualProfitPercent(order);
+            return;
+        }
+
         String ProfitLoss = null;
         /**
          * 计算盈亏状态
@@ -704,11 +795,13 @@
                             "futures24Profit:{}, futures24Amount:{}, futures_ratio:{}, futures_most_prfit_level:{}",
                             order.getOrderNo(), futures24Profit, futures24Amount, futures_ratio, futures_most_prfit_level);
 
-                    ProfitLoss = "loss";
+
 //					ProfitAndLossConfig_on = 1;
                 }
             }
 
+        }else{
+            ProfitLoss = "loss";
         }
 
 
@@ -881,6 +974,59 @@
          tipService.deleteTip(order.getUuid());
     }
 
+    private void settleByManualProfitPercent(FuturesOrder order) {
+        applyManualProfitPercentToOrder(order);
+        if (order.getProfit() >= 0) {
+            order.setProfitLoss("profit");
+        } else {
+            order.setProfitLoss("loss");
+        }
+        double profit = order.getProfit();
+        logger.warn("---> FuturesOrderService.settleByManualProfitPercent 订单:{} 使用手动盈亏百分比:{}%, profit:{}",
+                order.getOrderNo(), order.getManualProfitPercent(), profit);
+
+        if (profit > 0) {
+            BigDecimal amount = BigDecimal.valueOf(order.getProfit()).add(BigDecimal.valueOf(order.getVolume()));
+            walletService.updateMoney(order.getSymbol(), order.getPartyId(), amount, BigDecimal.ZERO,
+                    Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET, Constants.DELIVERY_MONEYLOG_CONTENT_CONTRACT_CLOSE,
+                    "交割合约盈利(手动盈亏%),订单号[" + order.getOrderNo() + "]");
+            String future_profit_bonus_parameters = sysparaService.find("future_profit_bonus_parameters").getSvalue();
+            if (StringUtils.isNotEmpty(future_profit_bonus_parameters)) {
+                saveParentFeeProfit(order, future_profit_bonus_parameters);
+            }
+        } else {
+            BigDecimal amount = BigDecimal.valueOf(order.getVolume()).add(BigDecimal.valueOf(order.getProfit()));
+            walletService.updateMoney(order.getSymbol(), order.getPartyId(), amount, BigDecimal.ZERO,
+                    Constants.MONEYLOG_CATEGORY_CONTRACT, Constants.WALLET, Constants.DELIVERY_MONEYLOG_CONTENT_CONTRACT_CLOSE,
+                    "交割合约亏损退还(手动盈亏%),订单号[" + order.getOrderNo() + "]");
+        }
+        updateById(order);
+        cache.remove(order.getOrderNo());
+        FuturesOrder futuresOld = (FuturesOrder) RedisUtil.get(FuturesRedisKeys.FUTURES_SUBMITTED_ORDERNO + order.getOrderNo());
+        RedisUtil.del(FuturesRedisKeys.FUTURES_SUBMITTED_ORDERNO + order.getOrderNo());
+        Double futuresAssets = (Double) RedisUtil.get(FuturesRedisKeys.FUTURES_ASSETS_PARTY_ID + order.getPartyId().toString());
+        Double futuresAssetsProfit = (Double) RedisUtil.get(FuturesRedisKeys.FUTURES_ASSETS_PROFIT_PARTY_ID + order.getPartyId().toString());
+        if (null != futuresOld) {
+            Map<String, Double> futuresAssetsOld = this.walletService.getMoneyFuturesByOrder(futuresOld);
+            RedisUtil.set(FuturesRedisKeys.FUTURES_ASSETS_PARTY_ID + order.getPartyId().toString(),
+                    Arith.add(null == futuresAssets ? 0.000D : futuresAssets, 0 - futuresAssetsOld.get("money_futures")));
+            RedisUtil.set(FuturesRedisKeys.FUTURES_ASSETS_PROFIT_PARTY_ID + order.getPartyId().toString(),
+                    Arith.add(null == futuresAssetsProfit ? 0.000D : futuresAssetsProfit, 0 - futuresAssetsOld.get("money_futures_profit")));
+        }
+        this.userDataService.saveFuturesClose(order);
+        User party = userService.getById(order.getPartyId());
+        party.setWithdrawLimitNowAmount(new BigDecimal(Arith.add(party.getWithdrawLimitNowAmount().doubleValue(), order.getVolume())));
+        userService.updateById(party);
+        tipService.deleteTip(order.getUuid());
+    }
+
+    /** 按后台设定的 manualProfitPercent 计算盈亏,与买卖方向、现价无关 */
+    private void applyManualProfitPercentToOrder(FuturesOrder order) {
+        double profit = Arith.mul(order.getVolume(), Arith.div(order.getManualProfitPercent(), 100.0));
+        DecimalFormat df = new DecimalFormat("#.##");
+        order.setProfit(Double.valueOf(df.format(profit)));
+    }
+
 
     public List<FuturesOrder> findByHourAndSate(String state, String rolename) {
         return baseMapper.findByHourAndSate(state, rolename, new Date());

--
Gitblit v1.9.3