package com.xcong.excoin.modules.contract.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import com.alibaba.fastjson.JSONObject; import com.xcong.excoin.common.contants.AppContants; import com.xcong.excoin.common.enumerates.CoinTypeEnum; import com.xcong.excoin.common.enumerates.MemberWalletCoinEnum; import com.xcong.excoin.common.enumerates.OrderClosingTypeEnum; import com.xcong.excoin.common.system.service.CommonService; import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity; import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange; import com.xcong.excoin.modules.contract.dao.ContractEntrustOrderDao; import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao; import com.xcong.excoin.modules.contract.dao.ContractOrderDao; import com.xcong.excoin.modules.contract.entity.ContractEntrustOrderEntity; import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity; import com.xcong.excoin.modules.contract.entity.ContractOrderEntity; import com.xcong.excoin.modules.contract.mapper.ContractHoldOrderEntityMapper; import com.xcong.excoin.modules.contract.service.RabbitOrderService; import com.xcong.excoin.modules.documentary.common.NoticeConstant; import com.xcong.excoin.modules.documentary.dao.FollowFollowerOrderRelationDao; import com.xcong.excoin.modules.documentary.dao.FollowFollowerProfitDao; import com.xcong.excoin.modules.documentary.dao.FollowTraderInfoDao; import com.xcong.excoin.modules.documentary.dao.FollowTraderProfitDetailDao; import com.xcong.excoin.modules.documentary.entity.FollowFollowerOrderRelationEntity; import com.xcong.excoin.modules.documentary.entity.FollowFollowerProfitEntity; import com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity; import com.xcong.excoin.modules.documentary.entity.FollowTraderProfitDetailEntity; import com.xcong.excoin.modules.documentary.service.FollowOrderOperationService; import com.xcong.excoin.modules.member.dao.MemberDao; import com.xcong.excoin.modules.member.dao.MemberSettingDao; import com.xcong.excoin.modules.member.dao.MemberWalletContractDao; import com.xcong.excoin.modules.member.entity.AgentReturnEntity; import com.xcong.excoin.modules.member.entity.MemberEntity; import com.xcong.excoin.modules.member.entity.MemberSettingEntity; import com.xcong.excoin.modules.member.entity.MemberWalletContractEntity; import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity; import com.xcong.excoin.rabbit.pricequeue.OrderModel; import com.xcong.excoin.rabbit.pricequeue.whole.HoldOrderDataModel; import com.xcong.excoin.rabbit.pricequeue.whole.WholePriceDataModel; import com.xcong.excoin.utils.*; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; /** * @author wzy * @date 2020-06-01 **/ @Slf4j @Service public class RabbitOrderServiceImpl implements RabbitOrderService { @Resource private MemberDao memberDao; @Resource private OrderWebsocketServiceImpl orderWebsocketService; @Resource private ContractHoldOrderDao contractHoldOrderDao; @Resource private ContractOrderDao contractOrderDao; @Resource private CommonService commonService; @Resource private MemberWalletContractDao memberWalletContractDao; @Resource private CacheSettingUtils cacheSettingUtils; @Resource private RedisUtils redisUtils; @Resource private MemberSettingDao memberSettingDao; @Resource private FollowFollowerOrderRelationDao followFollowerOrderRelationDao; @Resource private FollowOrderOperationService followOrderOperationService; @Resource private FollowTraderInfoDao followTraderInfoDao; @Resource private FollowTraderProfitDetailDao followTraderProfitDetailDao; @Resource private FollowFollowerProfitDao followFollowerProfitDao; @Resource private ContractEntrustOrderDao contractEntrustOrderDao; @Transactional(rollbackFor = Exception.class) @Override public void cancelHoldOrder(List ids) { if (CollUtil.isNotEmpty(ids)) { try { if (ids.size() == 1) { ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(ids.get(0)); if (holdOrderEntity != null) { // 判断仓位类型是否逐仓 if (holdOrderEntity.getPositionType() == ContractEntrustOrderEntity.POSITION_TYPE_ADD) { // 逐仓平仓 cancelHoldOrderMethod(holdOrderEntity); } else { // 全仓模式平仓 closingWholeOrder(holdOrderEntity); } } else { log.info("持仓订单为空: {}", ids.get(0)); } } else { List holdOrderEntities = contractHoldOrderDao.selectBatchIds(ids); if (CollUtil.isNotEmpty(holdOrderEntities)) { for (ContractHoldOrderEntity holdOrder : holdOrderEntities) { // 判断仓位类型是否逐仓 if (holdOrder.getPositionType() == ContractEntrustOrderEntity.POSITION_TYPE_ADD) { // 逐仓平仓 cancelHoldOrderMethod(holdOrder); } else { // 全仓模式平仓 closingWholeOrder(holdOrder); } } } } } catch (Exception e) { log.error("平仓异常", e); } } } @Transactional(rollbackFor = Exception.class) public void cancelHoldOrderMethod(ContractHoldOrderEntity holdOrderEntity) { String symbol = holdOrderEntity.getSymbol(); // 获取最新价 BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol))); MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId()); MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(holdOrderEntity.getMemberId(), CoinTypeEnum.USDT.name()); if (walletContract != null) { // 删除持仓表订单 contractHoldOrderDao.deleteById(holdOrderEntity.getId()); BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(symbol); // 盈亏 BigDecimal profitOrLoss = BigDecimal.ZERO; Integer orderType = null; Integer closingType = null; MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(memberEntity.getId()); // 开多 if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) { newPrice = newPrice.multiply(BigDecimal.ONE.subtract(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN))); // (最新价-开仓价)*规格*张数 profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())); orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_MORE; closingType = OrderClosingTypeEnum.CLOSE_MORE.getValue(); // 开空 } else { newPrice = newPrice.multiply(BigDecimal.ONE.add(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN))); // (开仓价-最新价)*规格*张数 profitOrLoss = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(lotNumber).multiply(new BigDecimal(holdOrderEntity.getSymbolCnt())); orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_LESS; closingType = OrderClosingTypeEnum.CLOSE_LESS.getValue(); } if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) { PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting(); if (profitOrLoss.compareTo(BigDecimal.ZERO) > -1) { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam())); } else { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam())); } } // 盈亏比例(回报率) BigDecimal rewardRatio = profitOrLoss.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN); FollowTraderInfoEntity traderInfoEntity = null; // 判断当前订单是否为跟单 if (ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY == holdOrderEntity.getContractType()) { // 若不为交易员,则计算跟随者订单返利 if (!MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) { traderInfoEntity = followTraderInfoDao.selectTraderInfoByOrderId(holdOrderEntity.getId()); if (profitOrLoss.compareTo(BigDecimal.ZERO) > 0) { // 计算需返利给交易员的金额 BigDecimal returnMoney = profitOrLoss.multiply(traderInfoEntity.getProfitRatio()); profitOrLoss = profitOrLoss.subtract(returnMoney); MemberWalletContractEntity traderWallet = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(traderInfoEntity.getMemberId(), CoinTypeEnum.USDT.name()); memberWalletContractDao.increaseWalletContractBalanceById(returnMoney, returnMoney, null, traderWallet.getId()); insertReturnProfitDetail(traderInfoEntity.getMemberId(), memberEntity.getId(), returnMoney, holdOrderEntity.getOrderNo()); //增加返佣提醒 // String orderNo = holdOrderEntity.getOrderNo(); // LogRecordUtils.insertFollowerNotice(traderInfoEntity.getMemberId(), // NoticeConstant.RETURN_MONEY_TITLE, // StrUtil.format(NoticeConstant.RETURN_MONEY_CONTENT, // orderNo, // holdOrderEntity.getSymbol(), // returnMoney.setScale(2, BigDecimal.ROUND_HALF_UP).toString())); // //带单返利的记录要在资产页面的其他记录 // LogRecordUtils.insertMemberAccountMoneyChange( // traderInfoEntity.getMemberId(), // StrUtil.format(NoticeConstant.RETURN_MONEY_CONTENT_MAMC, // orderNo, // holdOrderEntity.getSymbol(), // returnMoney.setScale(2, BigDecimal.ROUND_HALF_UP).toString()), // returnMoney.setScale(2, BigDecimal.ROUND_HALF_UP), // MemberWalletCoinEnum.WALLETCOINCODE.getValue(), // MemberAccountMoneyChange.STATUS_SUCCESS_INTEGER, // MemberAccountMoneyChange.TYPE_WALLET_AGENT); } } } ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); contractOrderEntity.setId(null); contractOrderEntity.setOrderType(orderType); contractOrderEntity.setClosingPrice(newPrice); contractOrderEntity.setClosingFeeAmount(holdOrderEntity.getOpeningFeeAmount()); contractOrderEntity.setClosingTime(new Date()); contractOrderEntity.setClosingType(closingType); contractOrderEntity.setRewardAmount(profitOrLoss); contractOrderEntity.setRewardRatio(rewardRatio); contractOrderDao.insert(contractOrderEntity); // 计算盈利或亏损后可用金额和总金额应该增加或减少的 BigDecimal addMoney = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()).add(profitOrLoss); memberWalletContractDao.increaseWalletContractBalanceById(addMoney, profitOrLoss.subtract(contractOrderEntity.getOpeningFeeAmount()), null, walletContract.getId()); // 流水 LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), addMoney, walletContract.getAvailableBalance().add(addMoney), holdOrderEntity.getSymbol(), "平仓", "平仓"); // 计算佣金 ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getClosingFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE); // 判断当前持仓是否为跟单订单 if (ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY == holdOrderEntity.getContractType()) { updateFollowOrderRelation(holdOrderEntity.getId(), contractOrderEntity.getId()); // 若为交易员,则平仓跟随者订单 if (MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) { followOrderOperationService.closingFollowOrders(holdOrderEntity.getOrderNo()); } else { //followFollowerProfitDao.updateFollowerProfitByTradeMemberId(holdOrderEntity.getBondAmount(), profitOrLoss, traderInfoEntity.getMemberId(), memberEntity.getId()); LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.CLOSE_ORDER_TITLE, StrUtil.format(NoticeConstant.CLOSE_ORDER_CONTENT, contractOrderEntity.getSymbol(), contractOrderEntity.getClosingPrice().setScale(2, BigDecimal.ROUND_HALF_UP).toString(), profitOrLoss.setScale(2, BigDecimal.ROUND_HALF_UP).toString(), traderInfoEntity.getNickname())); } } } } /** * 更新跟单订单关系 * * @param oldOrderId 当前持仓ID * @param newOrderId 历史订单ID */ public void updateFollowOrderRelation(Long oldOrderId, Long newOrderId) { FollowFollowerOrderRelationEntity orderRelationEntity = followFollowerOrderRelationDao.selectNowOneByorderId(oldOrderId); if (orderRelationEntity != null) { orderRelationEntity.setOrderId(newOrderId); orderRelationEntity.setOrderType(FollowFollowerOrderRelationEntity.ORDER_TYPE_HISTORY); followFollowerOrderRelationDao.updateById(orderRelationEntity); } } /** * 插入跟单返利明细 * * @param memberId 交易员会员ID * @param followMemberId 跟随者会员ID * @param amount 返利金额 * @param orderNo 订单编号 */ public void insertReturnProfitDetail(Long memberId, Long followMemberId, BigDecimal amount, String orderNo) { FollowTraderProfitDetailEntity profitDetailEntity = new FollowTraderProfitDetailEntity(); profitDetailEntity.setMemberId(memberId); profitDetailEntity.setFollowMemberId(followMemberId); profitDetailEntity.setAmount(amount); profitDetailEntity.setOrderNo(orderNo); followTraderProfitDetailDao.insert(profitDetailEntity); } /** * 全仓模式平仓逻辑 */ public void closingWholeOrder(ContractHoldOrderEntity holdOrderEntity) { String symbol = holdOrderEntity.getSymbol(); // 获取最新价 BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(symbol))); MemberEntity memberEntity = memberDao.selectById(holdOrderEntity.getMemberId()); MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(holdOrderEntity.getMemberId(), CoinTypeEnum.USDT.name()); if (walletContract != null) { BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(symbol); // 盈亏 BigDecimal profitOrLoss = BigDecimal.ZERO; Integer orderType = null; Integer closingType = null; // 获取平仓张数 Integer closeCnt = (Integer) redisUtils.get(AppContants.CLOSING_ORDER_PREFIX + holdOrderEntity.getId()); // 无法从redis中获取平仓张数,说明来自一键平仓 if (closeCnt == null) { closeCnt = holdOrderEntity.getSymbolCntSale(); holdOrderEntity.setSymbolCntSale(0); } MemberSettingEntity memberSettingEntity = memberSettingDao.selectMemberSettingByMemberId(memberEntity.getId()); // 开多 if (ContractHoldOrderEntity.OPENING_TYPE_MORE == holdOrderEntity.getOpeningType()) { newPrice = newPrice.multiply(BigDecimal.ONE.subtract(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN))); // (最新价-开仓价)*规格*张数 profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(closeCnt)); orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_MORE; closingType = OrderClosingTypeEnum.CLOSE_MORE.getValue(); // 开空 } else { newPrice = newPrice.multiply(BigDecimal.ONE.add(memberSettingEntity.getClosingSpread().divide(BigDecimal.valueOf(10000), 4, BigDecimal.ROUND_DOWN))); // (开仓价-最新价)*规格*张数 profitOrLoss = holdOrderEntity.getOpeningPrice().subtract(newPrice).multiply(lotNumber).multiply(new BigDecimal(closeCnt)); orderType = ContractOrderEntity.ORDER_TYPE_CLOSE_LESS; closingType = OrderClosingTypeEnum.CLOSE_LESS.getValue(); } if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) { PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting(); if (profitOrLoss.compareTo(BigDecimal.ZERO) > -1) { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam())); } else { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam())); } } log.info("profitOrLoss:{}", profitOrLoss); BigDecimal rewardRatio = profitOrLoss.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 4, BigDecimal.ROUND_DOWN); // 保证金 BigDecimal bondAmount = CalculateUtil.getBondAmount(holdOrderEntity.getOpeningPrice(), lotNumber, closeCnt, holdOrderEntity.getLeverRatio()); log.info("bondAmount:{}", bondAmount); // 平仓手续费 TODO 可能需要修复手续费 BigDecimal fee = BigDecimal.ZERO; if (holdOrderEntity.getSymbolCntSale() != 0) { BigDecimal totalFeeAmount = contractOrderDao.selectWholeFeeAmountByOrderNo(holdOrderEntity.getOrderNo()); fee = totalFeeAmount.divide(BigDecimal.valueOf(holdOrderEntity.getSymbolCnt()), 8, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(closeCnt)); } else { fee = holdOrderEntity.getOpeningFeeAmount(); } log.info("fee:{}", fee); ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); contractOrderEntity.setId(null); contractOrderEntity.setClosingPrice(newPrice); contractOrderEntity.setOrderType(orderType); contractOrderEntity.setClosingType(closingType); contractOrderEntity.setSymbolCnt(closeCnt); contractOrderEntity.setRewardAmount(profitOrLoss); contractOrderEntity.setRewardRatio(rewardRatio); contractOrderEntity.setBondAmount(bondAmount.add(fee)); contractOrderEntity.setClosingFeeAmount(fee); contractOrderEntity.setClosingTime(new Date()); contractOrderDao.insert(contractOrderEntity); if (holdOrderEntity.getSymbolCntSale() != 0) { holdOrderEntity.setOpeningFeeAmount(holdOrderEntity.getOpeningFeeAmount().subtract(fee)); holdOrderEntity.setBondAmount(holdOrderEntity.getBondAmount().subtract(bondAmount)); BigDecimal rewardAmount = holdOrderEntity.getRewardAmount() == null ? BigDecimal.ZERO : holdOrderEntity.getRewardAmount(); holdOrderEntity.setRewardAmount(rewardAmount.add(profitOrLoss)); contractHoldOrderDao.updateById(holdOrderEntity); } else { contractHoldOrderDao.deleteById(holdOrderEntity.getId()); // 若平掉所有张数,若存在委托平仓,则删除委托平仓记录 List entrustOrders = contractEntrustOrderDao.selectEntrustOrderByOrderNo(holdOrderEntity.getOrderNo()); if (CollUtil.isNotEmpty(entrustOrders)) { for (ContractEntrustOrderEntity entrustOrder : entrustOrders) { contractEntrustOrderDao.deleteById(entrustOrder.getId()); } } } BigDecimal changeAmount = profitOrLoss.add(bondAmount); log.info("changeAmount : {}", changeAmount); BigDecimal total = profitOrLoss.subtract(fee); log.info("totalMoney : {}", total); memberWalletContractDao.increaseWalletContractBalanceById(changeAmount, total, null, walletContract.getId()); ThreadPoolUtils.sendWholePrice(memberEntity.getId()); ThreadPoolUtils.sendWholeForceClosingPrice(holdOrderEntity.getSymbol(), memberEntity); // 计算佣金 ThreadPoolUtils.calReturnMoney(memberEntity.getId(), fee, contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE); } } @Override public void entrustCloseOrder(List list) { if (CollUtil.isNotEmpty(list)) { List ids = new ArrayList<>(); list.forEach(model -> ids.add(model.getOrderId())); List contractEntrustOrderEntities = contractEntrustOrderDao.selectEntrustOrderListByIds(ids); if (CollUtil.isNotEmpty(contractEntrustOrderEntities)) { for (ContractEntrustOrderEntity entrustOrderEntity : contractEntrustOrderEntities) { closeOrder(entrustOrderEntity); } } else { log.info("平仓委托单未找到"); } } } private void closeOrder(ContractEntrustOrderEntity entrustOrder) { log.info("执行平仓委托"); Long memberId = entrustOrder.getMemberId(); int orderType = entrustOrder.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_CLOSE_MORE ? ContractHoldOrderEntity.OPENING_TYPE_MORE : ContractHoldOrderEntity.OPENING_TYPE_LESS; String symbol = entrustOrder.getSymbol(); MemberEntity memberEntity = memberDao.selectById(memberId); MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, CoinTypeEnum.USDT.name()); BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(symbol); BigDecimal newPrice = entrustOrder.getEntrustPrice(); int closeCnt = entrustOrder.getSymbolCnt(); ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectWholeHoldOrderByOrderType(memberId, orderType, symbol); List types = redisUtils.lGet(AppContants.RABBIT_TYPE + holdOrderEntity.getId(), 0, -1); if (types.contains(9) || types.contains(10) || types.contains(11) || types.contains(12)) { log.info("存在止盈/止损 orderId : {}, types : {}", holdOrderEntity.getId(), JSONObject.toJSONString(types)); return; } BigDecimal profitOrLoss; int closingType; // 平多 if (entrustOrder.getEntrustType() == ContractEntrustOrderEntity.ENTRUST_TYPE_CLOSE_MORE) { profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(closeCnt)); closingType = OrderClosingTypeEnum.CLOSE_MORE.getValue(); // 平空 } else { profitOrLoss = newPrice.subtract(holdOrderEntity.getOpeningPrice()).multiply(lotNumber).multiply(new BigDecimal(closeCnt)); closingType = OrderClosingTypeEnum.CLOSE_LESS.getValue(); } if (memberEntity.getIsProfit() == MemberEntity.IS_PROFIT_Y) { PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting(); if (profitOrLoss.compareTo(BigDecimal.ZERO) > -1) { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.subtract(tradeSettingEntity.getProfitParam())); } else { profitOrLoss = profitOrLoss.multiply(BigDecimal.ONE.add(tradeSettingEntity.getProfitParam())); } } log.info("profitOrLoss:{}", profitOrLoss); // 保证金 BigDecimal bondAmount = CalculateUtil.getBondAmount(holdOrderEntity.getOpeningPrice(), lotNumber, closeCnt, holdOrderEntity.getLeverRatio()); log.info("bondAmount:{}", bondAmount); // 平仓手续费 TODO 可能需要修复手续费 BigDecimal fee = BigDecimal.ZERO; if (holdOrderEntity.getSymbolCntSale() != 0) { fee = holdOrderEntity.getOpeningFeeAmount().divide(BigDecimal.valueOf(holdOrderEntity.getSymbolCnt()), 8, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(closeCnt)); } else { fee = holdOrderEntity.getOpeningFeeAmount(); } log.info("fee:{}", fee); ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); contractOrderEntity.setId(null); contractOrderEntity.setEntrustOpeningPrice(newPrice); contractOrderEntity.setEntrustTime(new Date()); contractOrderEntity.setClosingPrice(newPrice); contractOrderEntity.setTradeType(ContractOrderEntity.TRADE_TYPE_LIMIT_PRICE); contractOrderEntity.setOrderType(entrustOrder.getEntrustType()); contractOrderEntity.setClosingType(closingType); contractOrderEntity.setSymbolCnt(closeCnt); contractOrderEntity.setRewardAmount(profitOrLoss); contractOrderEntity.setBondAmount(bondAmount); contractOrderEntity.setClosingTime(new Date()); contractOrderEntity.setClosingFeeAmount(fee); contractOrderDao.insert(contractOrderEntity); if (holdOrderEntity.getSymbolCntSale() - closeCnt != 0) { holdOrderEntity.setSymbolCntSale(holdOrderEntity.getSymbolCntSale() - closeCnt); holdOrderEntity.setOpeningFeeAmount(holdOrderEntity.getOpeningFeeAmount().subtract(fee)); holdOrderEntity.setBondAmount(holdOrderEntity.getBondAmount().subtract(bondAmount)); contractHoldOrderDao.updateById(holdOrderEntity); } else { contractHoldOrderDao.deleteById(holdOrderEntity.getId()); } BigDecimal changeAmount = profitOrLoss.add(bondAmount); log.info("changeAmount : {}", changeAmount); BigDecimal total = profitOrLoss.subtract(fee); log.info("totalMoney : {}", total); memberWalletContractDao.increaseWalletContractBalanceById(changeAmount, total, null, walletContract.getId()); contractEntrustOrderDao.deleteById(entrustOrder.getId()); ThreadPoolUtils.sendWholePrice(memberEntity.getId()); ThreadPoolUtils.sendWholeForceClosingPrice(holdOrderEntity.getSymbol(), memberEntity); // 计算佣金 ThreadPoolUtils.calReturnMoney(memberEntity.getId(), fee, contractOrderEntity, AgentReturnEntity.ORDER_TYPE_CLOSE); } @Transactional(rollbackFor = Exception.class) @Override public void wholeBombOrder(WholePriceDataModel wholePriceData) { MemberWalletContractEntity wallet = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(wholePriceData.getMemberId(), CoinTypeEnum.USDT.name()); MemberEntity memberEntity = memberDao.selectById(wholePriceData.getMemberId()); List list = wholePriceData.getList(); if (CollUtil.isNotEmpty(list)) { String batchNo = IdUtil.randomUUID(); for (HoldOrderDataModel holdOrderDataModel : list) { ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(holdOrderDataModel.getId()); if (holdOrderEntity == null) { log.info("持仓不存在:{}", holdOrderDataModel.getId()); redisUtils.del(AppContants.WHOLE_BOMB_PREFIX + wholePriceData.getMemberId()); continue; } holdOrderEntity.setStopLossPrice(CalculateUtil.calWholePriceTwo(memberEntity, holdOrderEntity, 2)); contractHoldOrderDao.deleteById(holdOrderDataModel.getId()); ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); if (holdOrderEntity.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) { contractOrderEntity.setClosingType(4); } else { contractOrderEntity.setClosingType(5); } BigDecimal rewardRatio = holdOrderDataModel.getRewardAmount().divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN); contractOrderEntity.setRewardRatio(rewardRatio); contractOrderEntity.setRewardAmount(holdOrderDataModel.getRewardAmount().add(contractOrderEntity.getHoldBond().negate())); contractOrderEntity.setClosingPrice(holdOrderDataModel.getClosingPrice()); contractOrderEntity.setForceClosingPrice(holdOrderDataModel.getClosingPrice()); // 订单状态转换 if (ContractOrderEntity.ORDER_TYPE_OPEN_MORE == contractOrderEntity.getOrderType()) { contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_MORE); } else { contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_LESS); } contractOrderEntity.setClosingTime(new Date()); contractOrderEntity.setBatchNo(batchNo); contractOrderDao.insert(contractOrderEntity); } List entrustOrder = contractEntrustOrderDao.selectEntrustOrderListByMemberId(wholePriceData.getMemberId()); BigDecimal totalAmount = BigDecimal.ZERO; if (CollUtil.isNotEmpty(entrustOrder)) { for (ContractEntrustOrderEntity contractEntrustOrderEntity : entrustOrder) { totalAmount = totalAmount.add(contractEntrustOrderEntity.getEntrustAmount()); } } memberWalletContractDao.increaseWalletContractBalanceById(wallet.getAvailableBalance().negate(), wallet.getTotalBalance().subtract(totalAmount).negate(), null, wallet.getId()); redisUtils.del(AppContants.WHOLE_BOMB_PREFIX + wholePriceData.getMemberId()); } else { log.info("参数有误:{}", memberEntity.getId()); } } @Transactional(rollbackFor = Exception.class) @Override public void wholeBombOrder(List list) { for (OrderModel orderModel : list) { MemberEntity memberEntity = memberDao.selectById(orderModel.getMemberId()); Long memberId = memberEntity.getId(); List holdOrderEntities = contractHoldOrderDao.selectHoldOrderListForWholeByMemberIdAndSymbol(memberId, null); MemberWalletContractEntity wallet = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberId, CoinTypeEnum.USDT.name()); Map value = redisUtils.hmget(AppContants.WHOLE_BOMB_PREFIX + memberId); if (CollUtil.isNotEmpty(holdOrderEntities)) { BigDecimal maxLess = BigDecimal.ZERO; ContractOrderEntity maxLessEntity = null; BigDecimal totalProfitOrLess = BigDecimal.ZERO; for (ContractHoldOrderEntity holdOrderEntity : holdOrderEntities) { // 删除次仓订单 contractHoldOrderDao.deleteById(holdOrderEntity.getId()); BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol()); String symbolPrice = (String) value.get(holdOrderEntity.getSymbol()); log.info("symbolPrice : {}, symbol : {}", symbolPrice, holdOrderEntity.getSymbol()); BigDecimal currentPrice = new BigDecimal(symbolPrice); BigDecimal profitOrLess = CalculateUtil.calOrderProfitOrLess(holdOrderEntity.getOpeningType(), currentPrice, holdOrderEntity.getOpeningPrice(), lotNumber, holdOrderEntity.getSymbolCntSale(), memberEntity.getIsProfit()); log.info("profitOrLess ---> {}", profitOrLess); ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); // 查询是否满足爆仓条件 if (holdOrderEntity.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) { contractOrderEntity.setClosingType(4); } else { contractOrderEntity.setClosingType(5); } // 盈亏比例(回报率) BigDecimal rewardRatio = profitOrLess.divide(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()), 8, BigDecimal.ROUND_DOWN); contractOrderEntity.setId(null); contractOrderEntity.setRewardRatio(rewardRatio); contractOrderEntity.setRewardAmount(profitOrLess); contractOrderEntity.setClosingPrice(currentPrice); contractOrderEntity.setForceClosingPrice(currentPrice); // 订单状态转换 if (ContractOrderEntity.ORDER_TYPE_OPEN_MORE == contractOrderEntity.getOrderType()) { contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_MORE); } else { contractOrderEntity.setOrderType(ContractOrderEntity.ORDER_TYPE_CLOSE_LESS); } contractOrderEntity.setClosingTime(new Date()); contractOrderEntity.setClosingFeeAmount(holdOrderEntity.getOpeningFeeAmount()); contractOrderDao.insert(contractOrderEntity); } List entrustOrder = contractEntrustOrderDao.selectEntrustOrderListByMemberId(memberId); BigDecimal totalAmount = BigDecimal.ZERO; if (CollUtil.isNotEmpty(entrustOrder)) { for (ContractEntrustOrderEntity contractEntrustOrderEntity : entrustOrder) { totalAmount.add(contractEntrustOrderEntity.getEntrustAmount()); } } memberWalletContractDao.increaseWalletContractBalanceById(wallet.getAvailableBalance().negate(), wallet.getTotalBalance().subtract(totalAmount).negate(), null, wallet.getId()); redisUtils.del(AppContants.WHOLE_BOMB_PREFIX + memberId); } else { log.info("无当前持仓"); } } } /** * 1 2 3 * 开仓价 - (权益 - 其他币种成本)/当前币种成本 * (开仓价 * 1/杠杆) * * @param dataModel * @param holdOrder * @return */ private BigDecimal getForceSetPrice(WholePriceDataModel dataModel, ContractHoldOrderEntity holdOrder, String currentSymbol) { Long memberId = holdOrder.getMemberId(); List holdOrderEntities = contractHoldOrderDao.selectHoldOrderListForWholeByMemberIdAndSymbol(memberId, null); List symbols = contractHoldOrderDao.selectWholeHoldOrderSymbolsByMemberId(memberId); BigDecimal result = BigDecimal.ZERO; if (CollUtil.isNotEmpty(holdOrderEntities)) { for (String symbol : symbols) { // 其他币种成本 BigDecimal totalBondAmount = BigDecimal.ZERO; // 当前币种保证金 BigDecimal symbolBondAmount = BigDecimal.ZERO; // 开仓均价 BigDecimal openPrice = BigDecimal.ZERO; // 杠杆 int leverRatio = 0; boolean isAloneLess = true; for (ContractHoldOrderEntity holdOrderEntity : holdOrderEntities) { BigDecimal bondAmount = holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount()); if (symbol.equalsIgnoreCase(holdOrderEntity.getSymbol())) { if (holdOrderEntity.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) { isAloneLess = false; } symbolBondAmount = symbolBondAmount.add(bondAmount.subtract(holdOrderEntity.getOpeningFeeAmount())); if (openPrice.compareTo(BigDecimal.ZERO) == 0) { openPrice = holdOrderEntity.getOpeningPrice(); } else { openPrice = openPrice.add(holdOrderEntity.getOpeningPrice()).divide(BigDecimal.valueOf(2), 8, BigDecimal.ROUND_DOWN); } leverRatio = holdOrderEntity.getLeverRatio(); } else { totalBondAmount = totalBondAmount.add(holdOrderEntity.getBondAmount().subtract(holdOrderEntity.getOpeningFeeAmount())); } } BigDecimal equity = dataModel.getEquity(); BigDecimal sub = equity.subtract(totalBondAmount); if (sub.compareTo(symbolBondAmount) <= 0) { BigDecimal multi = BigDecimal.valueOf(10); BigDecimal divide = equity.divide(equity.add(multi), 8, BigDecimal.ROUND_DOWN); sub = symbolBondAmount.multiply(divide); } BigDecimal divide = sub.divide(symbolBondAmount, 8, BigDecimal.ROUND_DOWN); BigDecimal divide2 = openPrice.divide(BigDecimal.valueOf(leverRatio), 8, BigDecimal.ROUND_DOWN); BigDecimal forcePrice = BigDecimal.ZERO; if (isAloneLess) { forcePrice = openPrice.add(divide.multiply(divide2)); } else { forcePrice = openPrice.subtract(divide.multiply(divide2)); } if (symbol.equalsIgnoreCase(currentSymbol)) { result = forcePrice; } } } return result; } }