| | |
| | | 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; |
| | |
| | | @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) { |
| | | BigDecimal volume = defaultZero(order.getVolume()); |
| | | BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice()); |
| | | if (volume.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 accruedFundingFee = estimateAccruedFundingFee(order); |
| | | BigDecimal baseEquity = defaultZero(wallet.getMoney()) |
| | | .add(otherEquity) |
| | | .add(defaultZero(order.getDeposit())) |
| | | .subtract(accruedFundingFee); |
| | | BigDecimal priceOffset = baseEquity.divide(volume, 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 volume = defaultZero(order.getVolume()); |
| | | BigDecimal tradeAvgPrice = defaultZero(order.getTradeAvgPrice()); |
| | | if (volume.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()).subtract(estimateAccruedFundingFee(order)); |
| | | if (availableDeposit.compareTo(BigDecimal.ZERO) <= 0) { |
| | | return tradeAvgPrice; |
| | | } |
| | | BigDecimal requiredLoss = availableDeposit.divide(thresholdRatio, 10, RoundingMode.HALF_UP); |
| | | BigDecimal priceOffset = requiredLoss.divide(volume, 10, RoundingMode.HALF_UP); |
| | | if (ContractOrder.DIRECTION_BUY.equalsIgnoreCase(order.getDirection())) { |
| | | return tradeAvgPrice.subtract(priceOffset); |
| | | } |
| | | return tradeAvgPrice.add(priceOffset); |
| | | } |
| | | |
| | | @Override |
| | | public void saveCalculation(String order_no) { |
| | | try { |
| | |
| | | Realtime realtime = list.get(0); |
| | | |
| | | BigDecimal close = new BigDecimal(realtime.getClose()); |
| | | settle(order, "watch", close); |
| | | |
| | | BigDecimal add = order.getTradeAvgPrice().add(order.getPips()); |
| | | BigDecimal subtract = order.getTradeAvgPrice().subtract(order.getPips()); |
| | |
| | | /** |
| | | * 根据价格变化百分比和保证金计算盈亏金额 |
| | | */ |
| | | BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice()) |
| | | .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN); |
| | | |
| | | BigDecimal priceChangeRatio = currentPrice.subtract(order.getTradeAvgPrice()) |
| | | .divide(order.getTradeAvgPrice(), 6, RoundingMode.DOWN); |
| | | |
| | | BigDecimal margin = order.getUnitAmount().multiply(order.getVolumeOpen()); // 这是用户实际的投资金额 |
| | | BigDecimal margin = order.getTradeAvgPrice().multiply(order.getVolume()); // 这是用户当前持仓对应的投资金额 |
| | | |
| | | BigDecimal profitAmount = margin.multiply(priceChangeRatio); |
| | | |
| | |
| | | } |
| | | BigDecimal profit1 = contractOrderService.getCacheProfit(order.getUuid()).getProfit(); |
| | | if (order_close_line_type == 1) { |
| | | /** |
| | | * 收益 |
| | | */ |
| | | BigDecimal profit = BigDecimal.ZERO; |
| | | |
| | | Wallet wallet = this.walletService.findByUserId(order.getPartyId().toString()); |
| | | // 计算所有除自己以外的profit |
| | | BigDecimal profitExptThis = profit.subtract(profit1).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 pipsAmount = order.getPipsAmount(); |
| | | if(pipsAmount.doubleValue() <= 0.00){ |
| | | pipsAmount = new BigDecimal("0.01"); |
| | | } |
| | | BigDecimal overLine = (left.multiply(pips).divide(pipsAmount, 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); |
| | | } |
| | | BigDecimal forceClose = calculateType1ForceClosePrice(order, wallet).setScale(decimal, RoundingMode.HALF_UP); |
| | | if (forceClose.compareTo(BigDecimal.ZERO) < 0) { |
| | | forceClose = BigDecimal.ZERO; |
| | | } |
| | | order.setForceClosePrice(forceClose.toPlainString()); |
| | | this.contractOrderService.updateByIdBuffer(order); |
| | | 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()))); |
| | | } |
| | | for (int i = 0; i < list.size(); i++) { |
| | | ContractOrder close_line = list.get(i); |
| | | profit = profit.add(close_line.getProfit().add(close_line.getDeposit())); |
| | | } |
| | | |
| | | if (profit.add(wallet.getMoney()).compareTo(BigDecimal.ZERO) <= 0) { |
| | | if (totalEquity.compareTo(BigDecimal.ZERO) <= 0) { |
| | | /** |
| | | * 触发全仓强平 |
| | | */ |
| | |
| | | |
| | | } |
| | | } else { |
| | | Integer decimal = itemService.getDecimal(order.getSymbol()); |
| | | BigDecimal forceClose = calculateType2ForceClosePrice(order).setScale(decimal, RoundingMode.HALF_UP); |
| | | if (forceClose.compareTo(BigDecimal.ZERO) < 0) { |
| | | forceClose = BigDecimal.ZERO; |
| | | } |
| | | order.setForceClosePrice(forceClose.toPlainString()); |
| | | this.contractOrderService.updateByIdBuffer(order); |
| | | BigDecimal divide = order.getDeposit().divide(profit1.abs(), 10, RoundingMode.HALF_UP); |
| | | if (profit1.compareTo(BigDecimal.ZERO) < 0 && divide.compareTo(order_close_line.divide(new BigDecimal(100), 10, RoundingMode.HALF_UP)) <= 0) { |
| | | /** |