Helius
2020-07-31 79e81397b1bf90e6833db97e4944f8fe7801a669
add submit follower order
3 files added
7 files modified
275 ■■■■■ changed files
src/main/java/com/xcong/excoin/modules/documentary/common/NoticeConstant.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowFollowerOrderRelationDao.java 3 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowFollowerSettingDao.java 4 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowTraderInfoDao.java 2 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/service/FollowOrderOperationService.java 13 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/service/impl/FollowOrderOperationServiceImpl.java 199 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/LogRecordUtils.java 20 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/documentary/FollowFollowerOrderRelationDao.xml 8 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/documentary/FollowFollowerSettingDao.xml 7 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/documentary/FollowTraderInfoDao.xml 6 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/documentary/common/NoticeConstant.java
New file
@@ -0,0 +1,13 @@
package com.xcong.excoin.modules.documentary.common;
/**
 * @author wzy
 * @date 2020-07-31
 **/
public class NoticeConstant {
    public static final String OPEN_ORDER_TITLE = "跟单开仓成功";
    public static final String OPEN_ORDER_CONTENT = "{}开仓成功,开仓价{},交易员{}";
}
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowFollowerOrderRelationDao.java
@@ -2,9 +2,12 @@
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerOrderRelationEntity;
import io.lettuce.core.dynamic.annotation.Param;
/**
 * @author helius
 */
public interface FollowFollowerOrderRelationDao extends BaseMapper<FollowFollowerOrderRelationEntity> {
    Integer selectFollowerHoldingSymbolCnt(@Param("tradeMemberId") Long tradeMemberId, @Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowFollowerSettingDao.java
@@ -5,6 +5,8 @@
import io.lettuce.core.dynamic.annotation.Param;
import java.util.List;
/**
 * @author helius
 */
@@ -13,4 +15,6 @@
    FollowFollowerSettingEntity selectDocumentaryOrderSetInfoBymemberId(@Param("memberId")Long memberId);
    FollowFollowerSettingEntity selectOneBymemberIdAndTradeId(@Param("memberId")Long memberId, @Param("traderId")Long traderId);
    List<FollowFollowerSettingEntity> selectAllFollowerSettingByTradeMemberId(@Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/documentary/dao/FollowTraderInfoDao.java
@@ -9,4 +9,6 @@
    FollowTraderInfoEntity selectFollowTraderInfoEntityBytreaderId(@Param("traderId")Long traderId);
    FollowTraderInfoEntity selectTraderInfoByMemberId(@Param("memberId") Long memberId);
}
src/main/java/com/xcong/excoin/modules/documentary/service/FollowOrderOperationService.java
New file
@@ -0,0 +1,13 @@
package com.xcong.excoin.modules.documentary.service;
import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
/**
 * @author helius
 */
public interface FollowOrderOperationService {
    public void addFollowerOrder(Long id);
}
src/main/java/com/xcong/excoin/modules/documentary/service/impl/FollowOrderOperationServiceImpl.java
New file
@@ -0,0 +1,199 @@
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));
    }
}
src/main/java/com/xcong/excoin/utils/LogRecordUtils.java
@@ -4,6 +4,8 @@
import com.xcong.excoin.modules.coin.dao.MemberAccountMoneyChangeDao;
import com.xcong.excoin.modules.coin.entity.MemberAccountFlowEntity;
import com.xcong.excoin.modules.coin.entity.MemberAccountMoneyChange;
import com.xcong.excoin.modules.documentary.dao.FollowFollowerNoticeDao;
import com.xcong.excoin.modules.documentary.entity.FollowFollowerNoticeEntity;
import java.math.BigDecimal;
@@ -15,7 +17,7 @@
 **/
public class LogRecordUtils {
    public static void insertMemberAccountMoneyChange(Long memberId,String content, BigDecimal amount, String symbol, Integer status, Integer type) {
    public static void insertMemberAccountMoneyChange(Long memberId, String content, BigDecimal amount, String symbol, Integer status, Integer type) {
        MemberAccountMoneyChange accountRecord = new MemberAccountMoneyChange();
        accountRecord.setContent(content);
        accountRecord.setMemberId(memberId);
@@ -36,4 +38,20 @@
        memberAccountFlowEntity.setRemark(remark);
        SpringContextHolder.getBean(MemberAccountFlowEntityDao.class).insert(memberAccountFlowEntity);
    }
    /**
     * 插入跟随者消息
     *
     * @param memberId 跟随者用户ID
     * @param title    消息标题
     * @param content  消息内容
     */
    public static void insertFollowerNotice(Long memberId, String title, String content) {
        FollowFollowerNoticeEntity noticeEntity = new FollowFollowerNoticeEntity();
        noticeEntity.setMemberId(memberId);
        noticeEntity.setTitle(title);
        noticeEntity.setContent(content);
        SpringContextHolder.getBean(FollowFollowerNoticeDao.class).insert(noticeEntity);
    }
}
src/main/resources/mapper/documentary/FollowFollowerOrderRelationDao.xml
@@ -2,4 +2,12 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xcong.excoin.modules.documentary.dao.FollowFollowerOrderRelationDao">
    <select id="selectFollowerHoldingSymbolCnt" resultType="java.lang.Integer">
        select
            IFNULL(sum(b.symbol_cnt),0)
        from follow_follower_order_relation a, contract_hold_order b
        where a.order_id=b.id and a.order_type=1 and a.trade_member_id=#{tradeMemberId}
        and a.member_id=#{memberId}
    </select>
</mapper>
src/main/resources/mapper/documentary/FollowFollowerSettingDao.xml
@@ -18,4 +18,11 @@
            member_id = #{memberId} 
            and trader_id = #{traderId} 
    </select>
    <select id="selectAllFollowerSettingByTradeMemberId" resultType="com.xcong.excoin.modules.documentary.entity.FollowFollowerSettingEntity">
        select * from follow_follower_setting
        where trader_member_id=#{memberId}
    </select>
</mapper>
src/main/resources/mapper/documentary/FollowTraderInfoDao.xml
@@ -5,5 +5,9 @@
    <select id="selectFollowTraderInfoEntityBytreaderId" resultType="com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity">
        select * from follow_trader_info where id = #{traderId}
    </select>
    <select id="selectTraderInfoByMemberId" resultType="com.xcong.excoin.modules.documentary.entity.FollowTraderInfoEntity">
        select * from follow_trader_info where member_id=#{memberId}
    </select>
</mapper>