| New file | 
 |  |  | 
 |  |  | package com.xcong.excoin.modules.documentary.service.impl; | 
 |  |  |  | 
 |  |  | import cn.hutool.core.collection.CollUtil; | 
 |  |  | import cn.hutool.core.util.StrUtil; | 
 |  |  | import com.alibaba.fastjson.JSONObject; | 
 |  |  | import com.xcong.excoin.common.enumerates.CoinTypeEnum; | 
 |  |  | import com.xcong.excoin.common.enumerates.RabbitPriceTypeEnum; | 
 |  |  | import com.xcong.excoin.common.response.Result; | 
 |  |  | import com.xcong.excoin.common.system.service.CommonService; | 
 |  |  | 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.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.FollowFollowerSettingDao; | 
 |  |  | import com.xcong.excoin.modules.documentary.dao.FollowTraderInfoDao; | 
 |  |  | import com.xcong.excoin.modules.documentary.entity.FollowFollowerProfitEntity; | 
 |  |  | import com.xcong.excoin.modules.documentary.entity.FollowFollowerSettingEntity; | 
 |  |  | import com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity; | 
 |  |  | import com.xcong.excoin.modules.documentary.service.FollowOrderOperationService; | 
 |  |  | import com.xcong.excoin.modules.member.dao.MemberDao; | 
 |  |  | 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.MemberWalletContractEntity; | 
 |  |  | import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity; | 
 |  |  | import com.xcong.excoin.rabbit.pricequeue.OrderModel; | 
 |  |  | import com.xcong.excoin.rabbit.producer.OrderProducer; | 
 |  |  | import com.xcong.excoin.utils.CacheSettingUtils; | 
 |  |  | import com.xcong.excoin.utils.CalculateUtil; | 
 |  |  | import com.xcong.excoin.utils.LogRecordUtils; | 
 |  |  | import com.xcong.excoin.utils.ThreadPoolUtils; | 
 |  |  | import lombok.extern.slf4j.Slf4j; | 
 |  |  | import org.springframework.stereotype.Service; | 
 |  |  |  | 
 |  |  | import javax.annotation.Resource; | 
 |  |  | import java.math.BigDecimal; | 
 |  |  | import java.math.RoundingMode; | 
 |  |  | import java.util.Date; | 
 |  |  | import java.util.List; | 
 |  |  |  | 
 |  |  | /** | 
 |  |  |  * @author helius | 
 |  |  |  */ | 
 |  |  | @Slf4j | 
 |  |  | @Service | 
 |  |  | public class FollowOrderOperationServiceImpl implements FollowOrderOperationService { | 
 |  |  |  | 
 |  |  |     @Resource | 
 |  |  |     private ContractHoldOrderDao contractHoldOrderDao; | 
 |  |  |     @Resource | 
 |  |  |     private FollowFollowerSettingDao followFollowerSettingDao; | 
 |  |  |     @Resource | 
 |  |  |     private CacheSettingUtils cacheSettingUtils; | 
 |  |  |     @Resource | 
 |  |  |     private FollowFollowerOrderRelationDao followFollowerOrderRelationDao; | 
 |  |  |     @Resource | 
 |  |  |     private MemberWalletContractDao memberWalletContractDao; | 
 |  |  |     @Resource | 
 |  |  |     private MemberDao memberDao; | 
 |  |  |     @Resource | 
 |  |  |     private CommonService commonService; | 
 |  |  |     @Resource | 
 |  |  |     private ContractOrderDao contractOrderDao; | 
 |  |  |     @Resource | 
 |  |  |     private OrderProducer producer; | 
 |  |  |     @Resource | 
 |  |  |     private FollowTraderInfoDao followTraderInfoDao; | 
 |  |  |  | 
 |  |  |     @Override | 
 |  |  |     public void addFollowerOrder(Long id) { | 
 |  |  |         // 查询交易员订单 | 
 |  |  |         ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(id); | 
 |  |  |  | 
 |  |  |         List<FollowFollowerSettingEntity> followerSettings = followFollowerSettingDao.selectAllFollowerSettingByTradeMemberId(holdOrderEntity.getMemberId()); | 
 |  |  |         // 开仓价 | 
 |  |  |         BigDecimal openPrice = holdOrderEntity.getOpeningPrice(); | 
 |  |  |         PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting(); | 
 |  |  |  | 
 |  |  |         // 交易员信息 | 
 |  |  |         FollowTraderInfoEntity followTraderInfoEntity = followTraderInfoDao.selectTraderInfoByMemberId(holdOrderEntity.getMemberId()); | 
 |  |  |  | 
 |  |  |         // 点差 | 
 |  |  |         BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(holdOrderEntity.getSymbol()); | 
 |  |  |         Long tradeMemberId = holdOrderEntity.getMemberId(); | 
 |  |  |         if (CollUtil.isNotEmpty(followerSettings)) { | 
 |  |  |             for (FollowFollowerSettingEntity followerSetting : followerSettings) { | 
 |  |  |                 // 当前持仓张数 | 
 |  |  |                 Integer holdingCnt = followFollowerOrderRelationDao.selectFollowerHoldingSymbolCnt(tradeMemberId, followerSetting.getMemberId()); | 
 |  |  |  | 
 |  |  |                 // 跟单张数 根据跟随者设置,若为固定张数,则为其固定张数,若为固定比例,则与交易员张数相乘。但必须小于最大持仓张数 | 
 |  |  |                 int symbolCnt = 0; | 
 |  |  |                 if (followerSetting.getFollowType().equals(FollowFollowerSettingEntity.FOLLOW_TYPE_PIECE)) { | 
 |  |  |                     symbolCnt = followerSetting.getFollowCnt(); | 
 |  |  |                 } else { | 
 |  |  |                     symbolCnt = followerSetting.getFollowCnt() * holdOrderEntity.getSymbolCnt(); | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 若张数+当前持仓张数大于最大持仓张数,则取最大持仓减去当前持仓,若差值小于等于0,则不下单 | 
 |  |  |                 if (symbolCnt + holdingCnt> followerSetting.getMaxFollowCnt()) { | 
 |  |  |                     symbolCnt = followerSetting.getMaxFollowCnt() - holdingCnt; | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 if (symbolCnt <= 0) { | 
 |  |  |                     continue; | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(followerSetting.getMemberId(), CoinTypeEnum.USDT.name()); | 
 |  |  |                 if (walletContract == null) { | 
 |  |  |                     log.info("钱包地址不存在:{}", followerSetting.getMemberId()); | 
 |  |  |                     continue; | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 // 开仓手续费 建仓价*规格*手数*手续费率 | 
 |  |  |                 BigDecimal openFeePrice = openPrice.multiply(lotNumber) | 
 |  |  |                         .multiply(new BigDecimal(symbolCnt)) | 
 |  |  |                         .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100))) | 
 |  |  |                         .setScale(8, BigDecimal.ROUND_DOWN); | 
 |  |  |  | 
 |  |  |                 // 保证金 | 
 |  |  |                 BigDecimal bondAmount = openPrice.multiply(lotNumber).multiply(new BigDecimal(symbolCnt)) | 
 |  |  |                         .multiply(BigDecimal.ONE.divide(new BigDecimal(holdOrderEntity.getLeverRatio()))) | 
 |  |  |                         .setScale(8, BigDecimal.ROUND_DOWN); | 
 |  |  |  | 
 |  |  |                 // 预付款 | 
 |  |  |                 BigDecimal prePaymentAmount = bondAmount.add(openFeePrice).add(openFeePrice); | 
 |  |  |                 if (prePaymentAmount.compareTo(walletContract.getAvailableBalance()) > -1) { | 
 |  |  |                     log.info("可用金额不足"); | 
 |  |  |                     continue; | 
 |  |  |                 } | 
 |  |  |  | 
 |  |  |                 MemberEntity memberEntity = memberDao.selectById(followerSetting.getMemberId()); | 
 |  |  |                 // 强平价 | 
 |  |  |                 BigDecimal forceClosingPrice = CalculateUtil.getForceSetPrice(bondAmount, openPrice, symbolCnt, lotNumber, holdOrderEntity.getOpeningType(), memberEntity); | 
 |  |  |  | 
 |  |  |                 ContractHoldOrderEntity followHoldOrder = new ContractHoldOrderEntity(); | 
 |  |  |                 followHoldOrder.setMemberId(memberEntity.getId()); | 
 |  |  |                 followHoldOrder.setOrderNo(commonService.generateOrderNo(memberEntity.getId())); | 
 |  |  |                 followHoldOrder.setPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD); | 
 |  |  |                 followHoldOrder.setTradeType(ContractHoldOrderEntity.TRADE_TYPE_MARK); | 
 |  |  |                 followHoldOrder.setSymbol(holdOrderEntity.getSymbol()); | 
 |  |  |                 followHoldOrder.setSymbolCnt(symbolCnt); | 
 |  |  |                 followHoldOrder.setSymbolSku(lotNumber); | 
 |  |  |                 followHoldOrder.setLeverRatio(holdOrderEntity.getLeverRatio()); | 
 |  |  |                 followHoldOrder.setForceClosingPrice(forceClosingPrice); | 
 |  |  |                 followHoldOrder.setOpeningFeeAmount(openFeePrice); | 
 |  |  |                 followHoldOrder.setOpeningPrice(openPrice); | 
 |  |  |                 followHoldOrder.setOpeningType(holdOrderEntity.getOpeningType()); | 
 |  |  |                 followHoldOrder.setMarkPrice(openPrice); | 
 |  |  |                 followHoldOrder.setIsCanClosing(ContractHoldOrderEntity.ORDER_CAN_CLOSING_Y); | 
 |  |  |                 followHoldOrder.setPrePaymentAmount(prePaymentAmount); | 
 |  |  |                 followHoldOrder.setBondAmount(bondAmount.add(openFeePrice)); | 
 |  |  |                 followHoldOrder.setOperateNo(1); | 
 |  |  |                 // 设置合约类型 | 
 |  |  |                 holdOrderEntity.setContractType(ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY); | 
 |  |  |  | 
 |  |  |                 ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(holdOrderEntity); | 
 |  |  |                 contractOrderEntity.setOpeningTime(new Date()); | 
 |  |  |                 contractHoldOrderDao.insert(holdOrderEntity); | 
 |  |  |                 int i = contractOrderDao.insert(contractOrderEntity); | 
 |  |  |  | 
 |  |  |                 if (i > 0) { | 
 |  |  |                     memberWalletContractDao.increaseWalletContractBalanceById(prePaymentAmount.negate(), openFeePrice.negate(), null, walletContract.getId()); | 
 |  |  |  | 
 |  |  |                     // 发送爆仓消息 | 
 |  |  |                     sendOrderBombMsg(holdOrderEntity.getId(), holdOrderEntity.getOpeningType(), forceClosingPrice, holdOrderEntity.getSymbol(), holdOrderEntity.getOperateNo()); | 
 |  |  |  | 
 |  |  |                     // 计算佣金 | 
 |  |  |                     ThreadPoolUtils.calReturnMoney(memberEntity.getId(), contractOrderEntity.getOpeningFeeAmount(), contractOrderEntity, AgentReturnEntity.ORDER_TYPE_OPEN); | 
 |  |  |  | 
 |  |  |                     // 插入财务流水 | 
 |  |  |                     if (holdOrderEntity.getOpeningType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) { | 
 |  |  |                         LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), holdOrderEntity.getSymbol(), "买涨持仓", "买涨:" + holdOrderEntity.getSymbol()); | 
 |  |  |                         LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.OPEN_ORDER_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_CONTENT, holdOrderEntity.getSymbol() + "开多", openPrice, followTraderInfoEntity.getNickname())); | 
 |  |  |                     } else { | 
 |  |  |                         LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), holdOrderEntity.getSymbol(), "买跌持仓", "买跌:" + holdOrderEntity.getSymbol()); | 
 |  |  |                         LogRecordUtils.insertFollowerNotice(memberEntity.getId(), NoticeConstant.OPEN_ORDER_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_CONTENT, holdOrderEntity.getSymbol() + "开空", openPrice, followTraderInfoEntity.getNickname())); | 
 |  |  |                     } | 
 |  |  |                 } | 
 |  |  |             } | 
 |  |  |         } | 
 |  |  |     } | 
 |  |  |  | 
 |  |  |     public void sendOrderBombMsg(Long id, int type, BigDecimal forceClosingPrice, String symbol, int operateNo) { | 
 |  |  |         OrderModel model = null; | 
 |  |  |         // 开多 | 
 |  |  |         if (ContractHoldOrderEntity.OPENING_TYPE_MORE == type) { | 
 |  |  |             model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_MORE_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo); | 
 |  |  |             // 开空 | 
 |  |  |         } else { | 
 |  |  |             model = new OrderModel(id, RabbitPriceTypeEnum.CLOSE_LESS_BOMB.getValue(), forceClosingPrice.setScale(8, RoundingMode.HALF_UP).toPlainString(), symbol, operateNo); | 
 |  |  |         } | 
 |  |  |         producer.sendPriceOperate(JSONObject.toJSONString(model)); | 
 |  |  |     } | 
 |  |  | } |