From ca0aa2ef38321b2d522b9db7fbc25a1a5a7510ce Mon Sep 17 00:00:00 2001
From: Helius <wangdoubleone@gmail.com>
Date: Wed, 12 Aug 2020 19:02:38 +0800
Subject: [PATCH] modify
---
src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java | 220 ++++++++++++++++++++++++++++++++++++-------
pom.xml | 6 +
src/main/java/com/xcong/excoin/utils/CalculateUtil.java | 58 +++++++++++
3 files changed, 245 insertions(+), 39 deletions(-)
diff --git a/pom.xml b/pom.xml
index 0438973..a0c4c75 100644
--- a/pom.xml
+++ b/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>
diff --git a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java b/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java
index 37b45a5..4857cdb 100644
--- a/src/main/java/com/xcong/excoin/modules/contract/service/impl/ContractHoldOrderServiceImpl.java
+++ b/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"));
}
+
/**
* 全仓模式--若当前已经存在持仓,则合并当前持仓
*/
diff --git a/src/main/java/com/xcong/excoin/utils/CalculateUtil.java b/src/main/java/com/xcong/excoin/utils/CalculateUtil.java
index 65e5cac..1d0c233 100644
--- a/src/main/java/com/xcong/excoin/utils/CalculateUtil.java
+++ b/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);
+ }
}
--
Gitblit v1.9.1