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.FollowFollowerOrderRelationEntity; 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) { log.info("进入跟单处理逻辑"); // 查询交易员订单 ContractHoldOrderEntity holdOrderEntity = contractHoldOrderDao.selectById(id); List 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(); } if (followerSetting.getMaxFollowCnt() != null && followerSetting.getMaxFollowCnt() !=0) { // 若张数+当前持仓张数大于最大持仓张数,则取最大持仓减去当前持仓,若差值小于等于0,则不下单 if (symbolCnt + holdingCnt > followerSetting.getMaxFollowCnt()) { symbolCnt = followerSetting.getMaxFollowCnt() - holdingCnt; } if (symbolCnt <= 0) { LogRecordUtils.insertFollowerNotice(followerSetting.getMemberId(), NoticeConstant.OPEN_ORDER_FOLLOW_FAIL_TITLE, StrUtil.format(NoticeConstant.OPEN_ORDER_FOLLOW_FAIL_CONTENT, followTraderInfoEntity.getNickname())); 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); // 设置合约类型 followHoldOrder.setContractType(ContractOrderEntity.CONTRACTTYPE_DOCUMENTARY); ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(followHoldOrder); contractOrderEntity.setOpeningTime(new Date()); contractHoldOrderDao.insert(followHoldOrder); int i = contractOrderDao.insert(contractOrderEntity); if (i > 0) { memberWalletContractDao.increaseWalletContractBalanceById(prePaymentAmount.negate(), openFeePrice.negate(), null, walletContract.getId()); FollowFollowerOrderRelationEntity relationEntity = new FollowFollowerOrderRelationEntity(); relationEntity.setIsShow(FollowFollowerOrderRelationEntity.IS_SHOW_Y); relationEntity.setMemberId(followHoldOrder.getMemberId()); relationEntity.setOrderId(followHoldOrder.getId()); relationEntity.setOrderType(FollowFollowerOrderRelationEntity.ORDER_TYPE_HOLD); relationEntity.setTradeId(followTraderInfoEntity.getId()); relationEntity.setTradeMemberId(followTraderInfoEntity.getMemberId()); relationEntity.setTradeOrderId(id); followFollowerOrderRelationDao.insert(relationEntity); // 发送爆仓消息 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)); } }