Helius
2020-08-12 ca0aa2ef38321b2d522b9db7fbc25a1a5a7510ce
modify
3 files modified
284 ■■■■ changed files
pom.xml 6 ●●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java 220 ●●●● patch | view | raw | blame | history
src/main/java/com/xcong/excoin/utils/CalculateUtil.java 58 ●●●●● patch | view | raw | blame | history
pom.xml
@@ -276,6 +276,12 @@
            <artifactId>httpmime</artifactId>
            <version>4.3.5</version>
        </dependency>
        <dependency>
            <groupId>org.jetbrains</groupId>
            <artifactId>annotations</artifactId>
            <version>13.0</version>
            <scope>compile</scope>
        </dependency>
        <!-- submail邮件 end -->
    </dependencies>
src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java
@@ -46,6 +46,7 @@
import sun.rmi.runtime.Log;
import javax.annotation.Resource;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
@@ -105,49 +106,197 @@
            if (CollUtil.isNotEmpty(holdList) || CollUtil.isNotEmpty(entrustList)) {
                return Result.fail("存在全仓订单,无法下单");
            }
            // 逐仓逻辑
            return doPositionTypeForAdd(submitOrderDto, memberEntity);
        } else {
            List<ContractHoldOrderEntity> holdList = contractHoldOrderDao.selectMemberHoldOrderByPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD, memberEntity.getId());
            List<ContractEntrustOrderEntity> entrustList = contractEntrustOrderDao.selectMemberEntrustOrderByPositionType(ContractEntrustOrderEntity.POSITION_TYPE_ADD, memberEntity.getId());
            if (CollUtil.isNotEmpty(holdList) || CollUtil.isNotEmpty(entrustList)) {
                return Result.fail("存在逐仓订单,无法下单");
            }
            // 全仓逻辑
            return doPositionTypeForWhole(submitOrderDto, memberEntity);
        }
    }
    /**
     * 提交订单 -- 全仓逻辑
     *
     * @return
     */
    public Result doPositionTypeForWhole(SubmitOrderDto submitOrderDto, MemberEntity memberEntity) {
        log.info("全仓逻辑");
        // 获取最新价
        BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(submitOrderDto.getSymbol())));
        MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
        PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
        Long id = memberEntity.getId();
        MemberEntity selectById = memberDao.selectById(id);
        BigDecimal spread = selectById.getSpread();
        // 规格
        BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(submitOrderDto.getSymbol());
        MemberEntity member = memberDao.selectById(memberEntity.getId());
        // 划点
        BigDecimal spread = member.getSpread();
        // 开仓价
        BigDecimal openingPrice = BigDecimal.ZERO;
        BigDecimal openingPrice = CalculateUtil.getOpeningPrice(submitOrderDto.getOrderType(), newPrice, spread);
        // 开多
        if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
            // 市场价*(1 + (点差/10000))
            openingPrice = newPrice.multiply(BigDecimal.ONE.add(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
        // 开仓手续费 建仓价*规格*手数*手续费率
        BigDecimal openFeePrice = CalculateUtil.getOpenFeePrice(openingPrice, lotNumber, submitOrderDto.getSymbolCnt(), tradeSettingEntity.getFeeRatio());
        log.info("开仓手续费:{}", openFeePrice);
            // 开空
        } else if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_LESS) {
            // 市场价*(1 - (点差/10000))
            openingPrice = newPrice.multiply(BigDecimal.ONE.subtract(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
        } else {
            return Result.fail(MessageSourceUtils.getString("unknown_type"));
        ContractHoldOrderEntity wholeHoldOrder = contractHoldOrderDao.selectWholeHoldOrderByOrderType(memberEntity.getId(), submitOrderDto.getOrderType());
        // 判断当前是否存在全仓订单,若存在则直接合并,若不存在则创建订单
        if (wholeHoldOrder != null) {
            BigDecimal totalPrice = openingPrice.multiply(BigDecimal.valueOf(submitOrderDto.getSymbolCnt()));
            // (当前开仓价*张数 + 原开仓价 * 原可平张数) / (张数 + 原可平张数)
            BigDecimal newOpenPrice = totalPrice.add(wholeHoldOrder.getOpeningPrice().multiply(BigDecimal.valueOf(wholeHoldOrder.getSymbolCnt()))).divide(BigDecimal.valueOf(submitOrderDto.getSymbolCnt() + wholeHoldOrder.getSymbolCntSale()), 8, BigDecimal.ROUND_DOWN);
            log.info("计算后开仓价:{}", newOpenPrice);
            BigDecimal bondAmount = CalculateUtil.getBondAmount(newOpenPrice, lotNumber, submitOrderDto.getSymbolCnt() + wholeHoldOrder.getSymbolCntSale(), submitOrderDto.getLeverRatio());
            log.info("新保证金:{}", bondAmount);
            BigDecimal fee = openFeePrice.add(wholeHoldOrder.getOpeningFeeAmount());
            log.info("手续费相加:{}", fee);
            BigDecimal prePaymentAmount = bondAmount.add(fee).add(fee);
            BigDecimal subBondAmount = bondAmount.subtract(wholeHoldOrder.getBondAmount());
            log.info("保证金差值:{}", subBondAmount);
            BigDecimal forceClosingPrice = CalculateUtil.getForceSetPriceForWhole(memberEntity);
            log.info("新预估强平价:{}", forceClosingPrice);
            ContractOrderEntity contractOrderEntity = ContractHoldOrderEntityMapper.INSTANCE.holdOrderToOrder(wholeHoldOrder);
            contractOrderEntity.setBondAmount(bondAmount.add(openFeePrice));
            contractOrderEntity.setForceClosingPrice(forceClosingPrice);
            contractOrderEntity.setOpeningPrice(newOpenPrice);
            contractOrderEntity.setSymbolCnt(submitOrderDto.getSymbolCnt());
            contractOrderEntity.setOpeningTime(new Date());
            contractOrderEntity.setMarkPrice(newPrice);
            contractOrderEntity.setOpeningFeeAmount(openFeePrice);
            contractOrderDao.insert(contractOrderEntity);
            wholeHoldOrder.setOpeningFeeAmount(fee);
            wholeHoldOrder.setOpeningPrice(newOpenPrice);
            wholeHoldOrder.setBondAmount(bondAmount);
            wholeHoldOrder.setSymbolCnt(wholeHoldOrder.getSymbolCnt() + submitOrderDto.getSymbolCnt());
            wholeHoldOrder.setSymbolCntSale(wholeHoldOrder.getSymbolCntSale() + submitOrderDto.getSymbolCnt());
            wholeHoldOrder.setForceClosingPrice(forceClosingPrice);
            wholeHoldOrder.setPrePaymentAmount(prePaymentAmount);
            wholeHoldOrder.setOperateNo(wholeHoldOrder.getOperateNo() + 1);
            int i = contractHoldOrderDao.updateById(wholeHoldOrder);
            if (i > 0) {
                memberWalletContractDao.increaseWalletContractBalanceById(subBondAmount.add(openFeePrice).negate(), openFeePrice.negate(), null, walletContract.getId());
                // 发送爆仓消息
                sendOrderBombMsg(wholeHoldOrder.getId(), wholeHoldOrder.getOpeningType(), forceClosingPrice, wholeHoldOrder.getSymbol(), wholeHoldOrder.getOperateNo());
                // 计算佣金
                ThreadPoolUtils.calReturnMoney(memberEntity.getId(), openFeePrice, contractOrderEntity, AgentReturnEntity.ORDER_TYPE_OPEN);
                // 插入财务流水
                if (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
                    LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买涨持仓", "买涨:" + submitOrderDto.getSymbol());
                } else {
                    LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买跌持仓", "买跌:" + submitOrderDto.getSymbol());
                }
                // 提交成功
                return Result.ok(MessageSourceUtils.getString("member_service_0024"));
            }
            // 提交失败
            return Result.fail(MessageSourceUtils.getString("member_service_0067"));
        }
        // 保证金 建仓价*规格*手数*(1/杠杆倍率)
        BigDecimal bondAmount = CalculateUtil.getBondAmount(openingPrice, lotNumber, submitOrderDto.getSymbolCnt(), submitOrderDto.getLeverRatio());
        log.info("保证金:{}", bondAmount);
        // 预付款为 --> 保证金+开仓手续费+平仓手续费 (开仓平仓手续费相同)
        BigDecimal prePaymentAmount = bondAmount.add(openFeePrice).add(openFeePrice);
        log.info("预付款:{}", prePaymentAmount);
        if (prePaymentAmount.compareTo(walletContract.getAvailableBalance()) > -1) {
            // 可用余额不足
            return Result.fail(MessageSourceUtils.getString("member_service_0085"));
        }
        // 预估强平价
        BigDecimal forceClosingPrice = CalculateUtil.getForceSetPriceForWhole(memberEntity);
        ContractHoldOrderEntity holdOrderEntity = new ContractHoldOrderEntity();
        holdOrderEntity.setMemberId(memberEntity.getId());
        holdOrderEntity.setOrderNo(commonService.generateOrderNo(memberEntity.getId()));
        holdOrderEntity.setPositionType(memberEntity.getContractPositionType());
        holdOrderEntity.setTradeType(ContractHoldOrderEntity.TRADE_TYPE_MARK);
        holdOrderEntity.setSymbol(submitOrderDto.getSymbol());
        holdOrderEntity.setSymbolCnt(submitOrderDto.getSymbolCnt());
        holdOrderEntity.setSymbolCntSale(submitOrderDto.getSymbolCnt());
        holdOrderEntity.setSymbolSku(lotNumber);
        holdOrderEntity.setLeverRatio(submitOrderDto.getLeverRatio());
        holdOrderEntity.setForceClosingPrice(forceClosingPrice);
        holdOrderEntity.setOpeningFeeAmount(openFeePrice);
        holdOrderEntity.setOpeningPrice(openingPrice);
        holdOrderEntity.setOpeningType(submitOrderDto.getOrderType());
        holdOrderEntity.setMarkPrice(newPrice);
        holdOrderEntity.setIsCanClosing(ContractHoldOrderEntity.ORDER_CAN_CLOSING_Y);
        holdOrderEntity.setPrePaymentAmount(prePaymentAmount);
        holdOrderEntity.setBondAmount(bondAmount.add(openFeePrice));
        holdOrderEntity.setOperateNo(1);
        // 设置合约类型
        holdOrderEntity.setContractType(ContractOrderEntity.CONTRACTTYPE_NORMAL);
        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 (submitOrderDto.getOrderType() == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
                LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买涨持仓", "买涨:" + submitOrderDto.getSymbol());
            } else {
                LogRecordUtils.insertMemberAccountFlow(memberEntity.getId(), prePaymentAmount, walletContract.getAvailableBalance().subtract(prePaymentAmount), submitOrderDto.getSymbol(), "买跌持仓", "买跌:" + submitOrderDto.getSymbol());
            }
            // 提交成功
            return Result.ok(MessageSourceUtils.getString("member_service_0024"));
        }
        // 提交失败
        return Result.fail(MessageSourceUtils.getString("member_service_0067"));
    }
    /**
     * 提交订单 -- 逐仓逻辑
     *
     * @return
     */
    public Result doPositionTypeForAdd(@NotNull SubmitOrderDto submitOrderDto, @NotNull MemberEntity memberEntity) {
        log.info("逐仓逻辑");
        // 获取最新价
        BigDecimal newPrice = new BigDecimal(redisUtils.getString(CoinTypeConvert.convertToKey(submitOrderDto.getSymbol())));
        MemberWalletContractEntity walletContract = memberWalletContractDao.findWalletContractByMemberIdAndSymbol(memberEntity.getId(), CoinTypeEnum.USDT.name());
        PlatformTradeSettingEntity tradeSettingEntity = cacheSettingUtils.getTradeSetting();
        // 规格
        BigDecimal lotNumber = cacheSettingUtils.getSymbolSku(submitOrderDto.getSymbol());
        MemberEntity member = memberDao.selectById(memberEntity.getId());
        // 划点
        BigDecimal spread = member.getSpread();
        // 开仓价
        BigDecimal openingPrice = CalculateUtil.getOpeningPrice(submitOrderDto.getOrderType(), newPrice, spread);
        log.info("开仓价:{}", openingPrice);
        // 开仓手续费 建仓价*规格*手数*手续费率
        BigDecimal openFeePrice = openingPrice.multiply(lotNumber)
                .multiply(new BigDecimal(submitOrderDto.getSymbolCnt()))
                .multiply(tradeSettingEntity.getFeeRatio().divide(new BigDecimal(100)))
                .setScale(8, BigDecimal.ROUND_DOWN);
        BigDecimal openFeePrice = CalculateUtil.getOpenFeePrice(openingPrice, lotNumber, submitOrderDto.getSymbolCnt(), tradeSettingEntity.getFeeRatio());
        log.info("开仓手续费:{}", openFeePrice);
        // 保证金 建仓价*规格*手数*(1/杠杆倍率)
@@ -163,27 +312,19 @@
            return Result.fail(MessageSourceUtils.getString("member_service_0085"));
        }
        boolean isOpenFollow = false;
        FollowTraderInfoEntity tradeInfo = null;
        if (memberEntity.getContractPositionType() == ContractEntrustOrderEntity.POSITION_TYPE_ALL) {
            ContractHoldOrderEntity wholeHoldOrder = contractHoldOrderDao.selectWholeHoldOrderByOrderType(memberEntity.getId(), submitOrderDto.getOrderType());
            // 判断当前是否存在全仓订单,若存在则直接合并,若不存在则创建订单
            if (wholeHoldOrder != null) {
                return mergeWholeHoldOrder(openingPrice, openFeePrice, newPrice, submitOrderDto, wholeHoldOrder, memberEntity);
            }
        } else {
            // 仅在逐仓模式中启用带单,判断是否开启了带单
            if (MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) {
                tradeInfo = followTraderInfoDao.selectTraderInfoByMemberId(memberEntity.getId());
                if (tradeInfo.getIsOpen().equals(FollowTraderInfoEntity.ISOPEN_Y)) {
                    isOpenFollow = true;
                }
            }
        }
        // 预估强平价
        BigDecimal forceClosingPrice = CalculateUtil.getForceSetPrice(bondAmount, openingPrice, submitOrderDto.getSymbolCnt(), lotNumber, submitOrderDto.getOrderType(), memberEntity);
        log.info("强平价:{}", forceClosingPrice);
        // 判断是否开启了带单
        boolean isOpenFollow = false;
        FollowTraderInfoEntity tradeInfo = null;
        if (MemberEntity.IS_TRADER_Y.equals(memberEntity.getIsTrader())) {
            tradeInfo = followTraderInfoDao.selectTraderInfoByMemberId(memberEntity.getId());
            if (tradeInfo.getIsOpen().equals(FollowTraderInfoEntity.ISOPEN_Y)) {
                isOpenFollow = true;
            }
        }
        ContractHoldOrderEntity holdOrderEntity = new ContractHoldOrderEntity();
        holdOrderEntity.setMemberId(memberEntity.getId());
@@ -249,6 +390,7 @@
        return Result.fail(MessageSourceUtils.getString("member_service_0067"));
    }
    /**
     * 全仓模式--若当前已经存在持仓,则合并当前持仓
     */
src/main/java/com/xcong/excoin/utils/CalculateUtil.java
@@ -1,6 +1,11 @@
package com.xcong.excoin.utils;
import com.xcong.excoin.common.exception.GlobalException;
import com.xcong.excoin.common.response.Result;
import com.xcong.excoin.modules.contract.dao.ContractHoldOrderDao;
import com.xcong.excoin.modules.contract.entity.ContractHoldOrderEntity;
import com.xcong.excoin.modules.member.dao.MemberWalletContractDao;
import com.xcong.excoin.modules.member.entity.MemberEntity;
import com.xcong.excoin.modules.platform.entity.PlatformTradeSettingEntity;
import lombok.extern.slf4j.Slf4j;
@@ -62,4 +67,57 @@
                .multiply(BigDecimal.ONE.divide(new BigDecimal(leverRatio)))
                .setScale(8, BigDecimal.ROUND_DOWN);
    }
    /**
     * 全仓模式 -- 预估强平价
     * 面值*(多单张数*多单开仓价-空单张数*空单开仓价)-余额-已实现盈亏 / 面值*(多单张数-空单张数)-(维持保证金率+TAKER手续费)*面值*(开多张数+开空张数)
     *
     * @return
     */
    public static BigDecimal getForceSetPriceForWhole(MemberEntity memberEntity) {
        ContractHoldOrderDao holdOrderDao = SpringContextHolder.getBean(ContractHoldOrderDao.class);
        MemberWalletContractDao walletContractDao = SpringContextHolder.getBean(MemberWalletContractDao.class);
        CacheSettingUtils cacheSettingUtils = SpringContextHolder.getBean(CacheSettingUtils.class);
        return null;
    }
    /**
     * 计算开仓价
     *
     * @param orderType 订单类型
     * @param newPrice  当前价
     * @param spread    划点
     * @return
     */
    public static BigDecimal getOpeningPrice(int orderType, BigDecimal newPrice, BigDecimal spread) {
        BigDecimal openingPrice = BigDecimal.ZERO;
        if (orderType == ContractHoldOrderEntity.OPENING_TYPE_MORE) {
            // 市场价*(1 + (点差/10000))
            openingPrice = newPrice.multiply(BigDecimal.ONE.add(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
            // 开空
        } else if (orderType == ContractHoldOrderEntity.OPENING_TYPE_LESS) {
            // 市场价*(1 - (点差/10000))
            openingPrice = newPrice.multiply(BigDecimal.ONE.subtract(spread.divide(new BigDecimal(10000)))).setScale(8, BigDecimal.ROUND_DOWN);
        } else {
            throw new GlobalException(MessageSourceUtils.getString("unknown_type"));
        }
        return openingPrice;
    }
    /**
     * 计算开仓手续费
     *
     * @param openingPrice 开仓价
     * @param lotNumber    规格
     * @param count        张数
     * @param feeRatio     手续费率
     * @return
     */
    public static BigDecimal getOpenFeePrice(BigDecimal openingPrice, BigDecimal lotNumber, int count, BigDecimal feeRatio) {
        return openingPrice.multiply(lotNumber)
                .multiply(new BigDecimal(count))
                .multiply(feeRatio.divide(new BigDecimal(100)))
                .setScale(8, BigDecimal.ROUND_DOWN);
    }
}