From 60d1f642052ad8c7bd8a11f02f965b122bebf9a4 Mon Sep 17 00:00:00 2001
From: zj <1772600164@qq.com>
Date: Thu, 09 Apr 2026 18:43:37 +0800
Subject: [PATCH] 1

---
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationServiceImpl.java |  109 +++++++++------------
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationService.java     |    5 +
 trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiAssetsController.java                     |    8 +
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java                |  172 ++++++++++++++++++++++++++-------
 trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java           |    2 
 5 files changed, 193 insertions(+), 103 deletions(-)

diff --git a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiAssetsController.java b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiAssetsController.java
index c0b17e1..3e4f928 100644
--- a/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiAssetsController.java
+++ b/trading-order-admin/src/main/java/com/yami/trading/api/controller/ApiAssetsController.java
@@ -5,6 +5,7 @@
 import com.yami.trading.bean.item.domain.Item;
 import com.yami.trading.bean.model.MoneyLog;
 import com.yami.trading.bean.model.RealNameAuthRecord;
+import com.yami.trading.bean.syspara.domain.Syspara;
 import com.yami.trading.common.domain.Result;
 import com.yami.trading.common.exception.BusinessException;
 import com.yami.trading.common.util.Arith;
@@ -21,6 +22,7 @@
 import com.yami.trading.service.finance.service.FinanceOrderService;
 import com.yami.trading.service.finance.service.FinanceService;
 import com.yami.trading.service.impl.ContractAndFutureProfit;
+import com.yami.trading.service.syspara.SysparaService;
 import com.yami.trading.service.user.UserDataService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -58,6 +60,9 @@
 
     @Autowired
     FinanceOrderMapper financeOrderMapper;
+
+    @Autowired
+    SysparaService sysparaService;
 
     /**
      * 交易栏 顶部数据统计
@@ -263,9 +268,10 @@
                     data = walletService.getMoneyAll(partyId);
                 }
             }
-
+            Syspara fundingFee= sysparaService.find("funding_fee");
             RealNameAuthRecord kyc = realNameAuthRecordService.getByUserId(partyId);
             data.put("status", kyc == null ? 0 : kyc.getStatus());
+            data.put("fundingFee", fundingFee.getSvalue());
             resultObject.setData(data);
         } catch (BusinessException e) {
             resultObject.setCode("1");
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
index 1aa139e..08eba0c 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractApplyOrderService.java
@@ -278,7 +278,7 @@
 
 
         order.setDeposit(BigDecimal.valueOf(close).multiply(order.getVolume()).divide(order.getLeverRate()));
-        order.setFee(BigDecimal.valueOf(item.getUnitFee()).multiply(order.getDeposit()).divide(order.getLeverRate()));
+        order.setFee(BigDecimal.valueOf(item.getUnitFee()).multiply(BigDecimal.valueOf(close).multiply(order.getVolume())));
         BigDecimal fee = order.getFee();
 //        if (order.getLeverRate() != null) {
 //            // 加上杠杆
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationService.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationService.java
index 4378586..b2699e8 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderCalculationService.java
@@ -23,4 +23,9 @@
 	public void setOrder_close_line_type(int order_close_line_type);
 	public BigDecimal calculateAllProfit(ContractOrder order);
 	public BigDecimal calculateTodayProfit(ContractOrder order, ZoneId zoneId);
+
+	/**
+	 * 按最新行情价刷新订单缓存盈亏(价差盈亏 + 累计资金费),用于平仓前与定时任务一致。
+	 */
+	void refreshMarkPriceProfit(ContractOrder order);
 }
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 43d9b73..16af431 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,17 +1,16 @@
 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.bean.syspara.domain.Syspara;
 import com.yami.trading.common.constants.ContractRedisKeys;
 import com.yami.trading.common.util.RedisUtil;
 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;
-import com.yami.trading.service.syspara.SysparaService;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.ObjectUtils;
 import org.apache.logging.log4j.LogManager;
@@ -21,13 +20,12 @@
 import org.springframework.context.annotation.Lazy;
 import org.springframework.stereotype.Service;
 
-import javax.annotation.Resource;
 import java.math.BigDecimal;
 import java.math.RoundingMode;
-import java.time.Duration;
 import java.time.Instant;
 import java.time.LocalDate;
 import java.time.ZoneId;
+import java.util.Date;
 import java.util.List;
 
 @Slf4j
@@ -51,31 +49,10 @@
     private DataService dataService;
     @Autowired
     private WalletService walletService;
-    @Resource
-    private SysparaService sysparaService;
     private Logger logger = LogManager.getLogger(ContractOrderCalculationServiceImpl.class);
 
     private BigDecimal defaultZero(BigDecimal value) {
         return value == null ? BigDecimal.ZERO : value;
-    }
-
-    private BigDecimal estimateAccruedFundingFee(ContractOrder order) {
-        if (order == null || order.getCreateTime() == null) {
-            return BigDecimal.ZERO;
-        }
-        BigDecimal borrowedAmount = defaultZero(order.getBorrowedAmount());
-        if (borrowedAmount.compareTo(BigDecimal.ZERO) <= 0) {
-            return BigDecimal.ZERO;
-        }
-        long holdHours = Duration.between(order.getCreateTime().toInstant(), Instant.now()).toHours();
-        long settlementPeriods = holdHours / 4;
-        if (settlementPeriods <= 0) {
-            return BigDecimal.ZERO;
-        }
-        BigDecimal conservativeRate = new BigDecimal("0.001");
-        return borrowedAmount.multiply(conservativeRate)
-                .multiply(BigDecimal.valueOf(settlementPeriods))
-                .setScale(8, RoundingMode.HALF_UP);
     }
 
     private BigDecimal calculateType1ForceClosePrice(ContractOrder order, Wallet wallet) {
@@ -97,11 +74,9 @@
             otherEquity = otherEquity.add(defaultZero(contractOrder.getProfit()).add(defaultZero(contractOrder.getDeposit())));
         }
 
-        BigDecimal accruedFundingFee = estimateAccruedFundingFee(order);
         BigDecimal baseEquity = defaultZero(wallet.getMoney())
                 .add(otherEquity)
-                .add(defaultZero(order.getDeposit()))
-                .subtract(accruedFundingFee);
+                .add(defaultZero(order.getDeposit()));
         BigDecimal priceOffset = baseEquity.divide(volume, 10, RoundingMode.HALF_UP);
         if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) {
             return tradeAvgPrice.subtract(priceOffset);
@@ -119,7 +94,7 @@
         if (thresholdRatio.compareTo(BigDecimal.ZERO) <= 0) {
             return tradeAvgPrice;
         }
-        BigDecimal availableDeposit = defaultZero(order.getDeposit()).subtract(estimateAccruedFundingFee(order));
+        BigDecimal availableDeposit = defaultZero(order.getDeposit());
         if (availableDeposit.compareTo(BigDecimal.ZERO) <= 0) {
             return tradeAvgPrice;
         }
@@ -195,11 +170,10 @@
         BigDecimal point = close.subtract(order.getTradeAvgPrice()).abs().divide(order.getPips(), 10, RoundingMode.HALF_UP);
         // 根据偏 差点数和手数算出盈亏金额
         BigDecimal amount = order.getPipsAmount().multiply(point).multiply(order.getVolume());
-        if (order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)) {
-            return amount;
-        } else {
-            return amount.negate();
-        }
+        BigDecimal pricePnl = order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)
+                ? amount : amount.negate();
+        BigDecimal funding = contractOrderService.calculateAccruedFundingPnl(order, close, new Date());
+        return pricePnl.add(funding);
 
     }
 
@@ -230,11 +204,10 @@
          * 根据偏 差点数和手数算出盈亏金额
          */
         BigDecimal amount = order.getPipsAmount().multiply(point).multiply(order.getVolume());
-        if (order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)) {
-            return amount;
-        } else {
-            return amount.negate();
-        }
+        BigDecimal pricePnl = order.getDirection().equalsIgnoreCase(ContractOrder.DIRECTION_BUY)
+                ? amount : amount.negate();
+        BigDecimal funding = contractOrderService.calculateAccruedFundingPnl(order, close, new Date());
+        return pricePnl.add(funding);
 
     }
 
@@ -262,28 +235,7 @@
             pips = new BigDecimal("0.01");
         }
 
-        /**
-         * 根据价格变化百分比和保证金计算盈亏金额
-         */
-        BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice())
-            .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN);
-
-        BigDecimal margin = order.getTradeAvgPrice().multiply(order.getVolume()); // 这是用户当前持仓对应的投资金额
-
-        BigDecimal profitAmount = margin.multiply(priceChangeRatio);
-
-        if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
-            order.setProfit(profitAmount.setScale(6,RoundingMode.DOWN));
-        } else{
-            order.setProfit(profitAmount.setScale(6,RoundingMode.DOWN).negate());
-        }
-
-
-        /**
-         * 多次平仓价格不对,后续修
-         */
-        order.setCloseAvgPrice(currentPrice);
-        this.contractOrderService.updateByIdBuffer(order);
+        applyMarkPriceToOrder(order, currentPrice);
 
         /**
          * 止盈价
@@ -332,7 +284,8 @@
                 return;
             }
         }
-        BigDecimal profit1 = contractOrderService.getCacheProfit(order.getUuid()).getProfit();
+        ContractOrderProfit cp = contractOrderService.getCacheProfit(order.getUuid());
+        BigDecimal profit1 = cp != null ? cp.getProfit() : defaultZero(order.getProfit());
         if (order_close_line_type == 1) {
             Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString());
             Integer decimal = itemService.getDecimal(order.getSymbol());
@@ -389,4 +342,36 @@
         this.order_close_line_type = order_close_line_type;
     }
 
+    private void applyMarkPriceToOrder(ContractOrder order, BigDecimal currentPrice) {
+        BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice())
+                .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN);
+        BigDecimal margin = order.getTradeAvgPrice().multiply(order.getVolume());
+        BigDecimal profitAmount = margin.multiply(priceChangeRatio);
+        BigDecimal priceProfit;
+        if (ContractOrder.DIRECTION_BUY.equals(order.getDirection())) {
+            priceProfit = profitAmount.setScale(6, RoundingMode.DOWN);
+        } else {
+            priceProfit = profitAmount.setScale(6, RoundingMode.DOWN).negate();
+        }
+        BigDecimal fundingPnl = contractOrderService.calculateAccruedFundingPnl(order, currentPrice, new Date());
+        order.setProfit(priceProfit.add(fundingPnl));
+        order.setCloseAvgPrice(currentPrice);
+        this.contractOrderService.updateByIdBuffer(order);
+    }
+
+    @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, BigDecimal.valueOf(list.get(0).getClose()));
+    }
+
 }
diff --git a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
index 4ccdca1..51a8f29 100644
--- a/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
+++ b/trading-order-service/src/main/java/com/yami/trading/service/contract/ContractOrderService.java
@@ -63,7 +63,10 @@
 import java.math.RoundingMode;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
-import java.time.Duration;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.temporal.ChronoUnit;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
@@ -74,7 +77,6 @@
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ThreadLocalRandom;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -88,6 +90,12 @@
 @Transactional
 @Slf4j
 public class ContractOrderService extends ServiceImpl<ContractOrderMapper, ContractOrder> {
+
+    /**
+     * 资金费结算间隔(分钟):从当地日界 0:00 起每 N 分钟为一个结算点。
+     * 240 即每 4 小时一档(0、4、8、12、16、20 点)。
+     */
+    private static final int FUNDING_SETTLEMENT_INTERVAL_MINUTES = 240;
 
     private Logger logger = LogManager.getLogger(ContractOrderService.class);
 
@@ -163,6 +171,10 @@
     private ContractApplyOrderService contractApplyOrderService;
     @Autowired
     private SysparaService sysparaService;
+
+    @Autowired
+    @Lazy
+    private ContractOrderCalculationService contractOrderCalculationService;
 
     public IPage<ContractOrderDTO> listRecordCur(Page page, ContractOrderQuery query) {
         if (query.getStartTime() != null) {
@@ -375,15 +387,30 @@
             return null;
         }
 
-        /**
-         * 收益
-         */
+        contractOrderCalculationService.refreshMarkPriceProfit(order);
+
         BigDecimal volume = order.getVolume();
-        BigDecimal fundingFee = this.calculateFundingFee(order, volume, new Date());
-        BigDecimal profit = settle(order, order.getVolume()).subtract(fundingFee);
-        order.setAmountClose(order.getAmountClose().subtract(fundingFee));
-        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingFee));
+        if (volume.compareTo(BigDecimal.ZERO) <= 0) {
+            return null;
+        }
+
+        ContractOrderProfit cache = getCacheProfit(order.getUuid());
+        BigDecimal markPrice = order.getTradeAvgPrice();
+        if (cache != null && cache.getCloseAvgPrice() != null
+                && cache.getCloseAvgPrice().compareTo(BigDecimal.ZERO) > 0) {
+            markPrice = cache.getCloseAvgPrice();
+        }
+        BigDecimal fundingPnlChunk = calculateAccruedFundingPnl(order, markPrice, new Date());
+
         String symbol = order.getSymbol();
+        Item item = itemService.findBySymbol(symbol);
+        BigDecimal closeFee = calculateCloseTradingFee(item, markPrice, volume);
+
+        BigDecimal profit = settle(order, volume).subtract(closeFee);
+
+        order.setFee(defaultZero(order.getFee()).add(closeFee));
+        order.setAmountClose(order.getAmountClose().subtract(closeFee));
+        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingPnlChunk));
 //        Item item = itemService.findBySymbol(symbol);
 //        profit = exchangeRateService.getUsdtByType(profit, item.getType());
         if (ContractOrder.ORDER_FOLLOW == order.getFollow()) { // 跟单订单
@@ -696,37 +723,90 @@
         return profit;
     }
 
-    private BigDecimal calculateFundingFee(ContractOrder order, BigDecimal closeVolume, Date closeTime) {
-        if (order == null || closeVolume == null || closeTime == null) {
+    /**
+     * 累计资金费带来的盈亏(正数表示用户获利):多仓为 -合约价值×费率×次数,空仓为 +合约价值×费率×次数。
+     * 费率来自 syspara funding_fee;结算锚点为系统默认时区、从当天 0:00 起每 {@link #FUNDING_SETTLEMENT_INTERVAL_MINUTES} 分钟一档。
+     */
+    public BigDecimal calculateAccruedFundingPnl(ContractOrder order, BigDecimal markPrice, Date asOf) {
+        if (order == null || markPrice == null || asOf == null || order.getCreateTime() == null) {
             return BigDecimal.ZERO;
         }
-        if (closeVolume.compareTo(BigDecimal.ZERO) <= 0
-                || order.getVolumeOpen() == null
-                || order.getVolumeOpen().compareTo(BigDecimal.ZERO) <= 0
-                || order.getCreateTime() == null) {
+        BigDecimal vol = defaultZero(order.getVolume());
+        if (vol.compareTo(BigDecimal.ZERO) <= 0 || markPrice.compareTo(BigDecimal.ZERO) <= 0) {
             return BigDecimal.ZERO;
         }
-
-        long holdHours = Duration.between(order.getCreateTime().toInstant(), closeTime.toInstant()).toHours();
-        long settlementPeriods = holdHours / 4;
-        if (settlementPeriods <= 0) {
+        long periods = countFundingSettlementPoints(
+                order.getCreateTime().toInstant(),
+                asOf.toInstant(),
+                ZoneId.systemDefault(),
+                FUNDING_SETTLEMENT_INTERVAL_MINUTES);
+        if (periods <= 0) {
             return BigDecimal.ZERO;
         }
+        BigDecimal notional = markPrice.multiply(vol);
+        BigDecimal rate = getContractFundingRate();
+        BigDecimal signed = ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())
+                ? rate.negate() : rate;
+        return notional.multiply(signed).multiply(BigDecimal.valueOf(periods)).setScale(8, RoundingMode.HALF_UP);
+    }
 
-        BigDecimal fundingRateTotal = BigDecimal.ZERO;
-        for (int i = 0; i < settlementPeriods; i++) {
-            double periodRate = ThreadLocalRandom.current().nextDouble(-0.001D, 0.0010000001D);
-            fundingRateTotal = fundingRateTotal.add(BigDecimal.valueOf(periodRate));
-        }
-
-        BigDecimal currentVolume = defaultZero(order.getVolume());
-        if (currentVolume.compareTo(BigDecimal.ZERO) <= 0) {
+    public BigDecimal getContractFundingRate() {
+        try {
+            Syspara p = sysparaService.find("funding_fee");
+            if (p == null || StringUtils.isEmptyString(p.getSvalue())) {
+                return BigDecimal.ZERO;
+            }
+            return new BigDecimal(p.getSvalue().trim());
+        } catch (Exception e) {
+            log.warn("parse funding_fee syspara failed", e);
             return BigDecimal.ZERO;
         }
+    }
 
-        BigDecimal closeRatio = closeVolume.divide(currentVolume, 10, RoundingMode.HALF_UP);
-        BigDecimal borrowedBase = getCurrentBorrowedAmount(order).multiply(closeRatio);
-        return borrowedBase.multiply(fundingRateTotal).setScale(8, RoundingMode.HALF_UP);
+    /**
+     * 平仓手续费:手续费率×平仓价×数量(与开仓计费规则一致:U 本位用 unitPercentage,否则 unitFee×价×量)。
+     */
+    public BigDecimal calculateCloseTradingFee(Item item, BigDecimal closePrice, BigDecimal closeVolume) {
+        if (item == null || closePrice == null || closeVolume == null
+                || closeVolume.compareTo(BigDecimal.ZERO) <= 0) {
+            return BigDecimal.ZERO;
+        }
+        Syspara syspara = sysparaService.find("u_standard_contract");
+        if (ObjectUtils.isNotEmpty(syspara) && "1".equals(syspara.getSvalue())) {
+            return closePrice.multiply(closeVolume).multiply(BigDecimal.valueOf(item.getUnitPercentage()))
+                    .setScale(8, RoundingMode.HALF_UP);
+        }
+        return BigDecimal.valueOf(item.getUnitFee()).multiply(closePrice).multiply(closeVolume)
+                .setScale(8, RoundingMode.HALF_UP);
+    }
+
+    private static ZonedDateTime nextFundingSettlementStrictlyAfter(ZonedDateTime t, int intervalMinutes) {
+        int step = intervalMinutes <= 0 ? 240 : intervalMinutes;
+        ZonedDateTime tTrunc = t.withSecond(0).withNano(0);
+        ZonedDateTime dayStart = tTrunc.toLocalDate().atStartOfDay(tTrunc.getZone());
+        long minutesFromDayStart = ChronoUnit.MINUTES.between(dayStart, tTrunc);
+        long slotIndex = minutesFromDayStart / step;
+        ZonedDateTime slotStart = dayStart.plusMinutes(slotIndex * step);
+        ZonedDateTime next = slotStart;
+        while (!next.isAfter(t)) {
+            next = next.plusMinutes(step);
+        }
+        return next;
+    }
+
+    private static long countFundingSettlementPoints(Instant open, Instant end, ZoneId zone, int intervalMinutes) {
+        if (open == null || end == null || !end.isAfter(open)) {
+            return 0;
+        }
+        int step = intervalMinutes <= 0 ? 240 : intervalMinutes;
+        ZonedDateTime zEnd = end.atZone(zone);
+        ZonedDateTime cursor = nextFundingSettlementStrictlyAfter(open.atZone(zone), step);
+        long cnt = 0;
+        while (!cursor.isAfter(zEnd)) {
+            cnt++;
+            cursor = cursor.plusMinutes(step);
+        }
+        return cnt;
     }
 
     private BigDecimal defaultZero(BigDecimal value) {
@@ -932,20 +1012,34 @@
              */
             return applyOrder;
         }
+        BigDecimal preVolume = order.getVolume();
+        contractOrderCalculationService.refreshMarkPriceProfit(order);
+
         BigDecimal volume;
         if (applyOrder.getVolume().compareTo(order.getVolume()) > 0) {
             volume = order.getVolume();
         } else {
             volume = applyOrder.getVolume();
         }
-        /**
-         * 平仓退回的金额
-         */
-        BigDecimal fundingFee = this.calculateFundingFee(order, volume, new Date());
-        BigDecimal profit = this.settle(order, volume);
-        BigDecimal netProfit = profit.subtract(fundingFee);
-        order.setAmountClose(order.getAmountClose().subtract(fundingFee));
-        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingFee));
+        BigDecimal markPrice = BigDecimal.valueOf(realtime.getClose());
+        ContractOrderProfit cache = getCacheProfit(order.getUuid());
+        if (cache != null && cache.getCloseAvgPrice() != null
+                && cache.getCloseAvgPrice().compareTo(BigDecimal.ZERO) > 0) {
+            markPrice = cache.getCloseAvgPrice();
+        }
+        BigDecimal fundingAccruedTotal = calculateAccruedFundingPnl(order, markPrice, new Date());
+        BigDecimal fundingPnlChunk = fundingAccruedTotal.multiply(volume.divide(preVolume, 10, RoundingMode.HALF_UP))
+                .setScale(8, RoundingMode.HALF_UP);
+
+        Item item = itemService.findBySymbol(order.getSymbol());
+        BigDecimal closeFee = calculateCloseTradingFee(item, markPrice, volume);
+
+        BigDecimal profit = this.settle(order, volume).subtract(closeFee);
+        BigDecimal netProfit = profit;
+
+        order.setFee(defaultZero(order.getFee()).add(closeFee));
+        order.setAmountClose(order.getAmountClose().subtract(closeFee));
+        order.setFundingFee(defaultZero(order.getFundingFee()).add(fundingPnlChunk));
         update(order);
         Wallet wallet = this.walletService.findByUserId(order.getPartyId());
         BigDecimal amount_before = wallet.getMoney();
@@ -961,7 +1055,7 @@
 
 
         applyOrder.setVolume(applyOrder.getVolume().subtract(volume));
-        applyOrder.setFundingFee(defaultZero(applyOrder.getFundingFee()).add(fundingFee));
+        applyOrder.setFundingFee(defaultZero(applyOrder.getFundingFee()).add(fundingPnlChunk));
         if (applyOrder.getVolume().compareTo(BigDecimal.ZERO) <= 0) {
             applyOrder.setState(ContractApplyOrder.STATE_CREATED);
         }

--
Gitblit v1.9.3