| | |
| | | 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; |
| | |
| | | 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 |
| | |
| | | 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) { |
| | |
| | | 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); |
| | |
| | | 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; |
| | | } |
| | |
| | | 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); |
| | | |
| | | } |
| | | |
| | |
| | | * 根据偏 差点数和手数算出盈亏金额 |
| | | */ |
| | | 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); |
| | | |
| | | } |
| | | |
| | |
| | | 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); |
| | | |
| | | /** |
| | | * 止盈价 |
| | |
| | | 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()); |
| | |
| | | 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())); |
| | | } |
| | | |
| | | } |