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