1
zj
9 days ago 1f19b78818609bf6d0849f8e58b349132a800538
1
5 files modified
5 files added
260 ■■■■ changed files
.idea/A-stock.iml 9 ●●●●● patch | view | raw | blame | history
.idea/git_toolbox_prj.xml 15 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/controller/protol/UserController.java 7 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/service/IUserPositionService.java 2 ●●● patch | view | raw | blame | history
src/main/java/com/nq/service/impl/UserPositionServiceImpl.java 69 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/DateTimeUtil.java 8 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/TradeFeeUtil.java 29 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/utils/pay/OcocnPayUtil.java 97 ●●●●● patch | view | raw | blame | history
src/main/java/com/nq/vo/pay/OcocnPayVO.java 13 ●●●●● patch | view | raw | blame | history
src/main/resources/mapper/UserPositionMapper.xml 11 ●●●●● patch | view | raw | blame | history
.idea/A-stock.iml
New file
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
  <component name="NewModuleRootManager" inherit-compiler-output="true">
    <exclude-output />
    <content url="file://$MODULE_DIR$" />
    <orderEntry type="inheritedJdk" />
    <orderEntry type="sourceFolder" forTests="false" />
  </component>
</module>
.idea/git_toolbox_prj.xml
New file
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
  <component name="GitToolBoxProjectSettings">
    <option name="commitMessageIssueKeyValidationOverride">
      <BoolValueOverride>
        <option name="enabled" value="true" />
      </BoolValueOverride>
    </option>
    <option name="commitMessageValidationEnabledOverride">
      <BoolValueOverride>
        <option name="enabled" value="true" />
      </BoolValueOverride>
    </option>
  </component>
</project>
src/main/java/com/nq/controller/protol/UserController.java
@@ -92,8 +92,7 @@
    public ServerResponse buy(@RequestParam("stockId") Integer stockId, @RequestParam("buyNum") Integer buyNum, @RequestParam("buyType") Integer buyType, @RequestParam("lever") Integer lever,@RequestParam(value = "profitTarget",required = false) BigDecimal profitTarget,@RequestParam(value = "stopTarget",required = false) BigDecimal stopTarget, HttpServletRequest request) {
        ServerResponse serverResponse = null;
        try {
//            serverResponse = this.iUserPositionService.buy(stockId, buyNum, buyType, lever,profitTarget,stopTarget, request);
            serverResponse = this.iUserPositionService.pending(stockId, buyNum, buyType, lever,profitTarget,stopTarget, request);
            serverResponse = this.iUserPositionService.buy(stockId, buyNum, buyType, lever, profitTarget, stopTarget, request);
        } catch (Exception e) {
            log.error("用户下单操作 = {}", e);
        }
@@ -103,10 +102,10 @@
    //用户下单买入股票
    @RequestMapping({"fee.do"})
    @ResponseBody
    public ServerResponse fee(@RequestParam("buyNum") Integer buyNum,@RequestParam("nowPrice") BigDecimal nowPrice,HttpServletRequest request) {
    public ServerResponse fee(@RequestParam("buyNum") Integer buyNum, @RequestParam("nowPrice") BigDecimal nowPrice, @RequestParam(value = "lever", required = false, defaultValue = "1") Integer lever, HttpServletRequest request) {
        ServerResponse serverResponse = null;
        try {
            serverResponse = this.iUserPositionService.fee(buyNum,nowPrice);
            serverResponse = this.iUserPositionService.fee(buyNum, nowPrice, lever);
        } catch (Exception e) {
            log.error("用户下单操作 = {}", e);
        }
src/main/java/com/nq/service/IUserPositionService.java
@@ -26,7 +26,7 @@
  
  ServerResponse lock(Integer paramInteger1, Integer paramInteger2, String paramString,Integer paramInteger3);
  ServerResponse fee(Integer buyNum,BigDecimal nowPrice);
  ServerResponse fee(Integer buyNum, BigDecimal nowPrice, Integer lever);
  ServerResponse del(Integer paramInteger);
  
src/main/java/com/nq/service/impl/UserPositionServiceImpl.java
@@ -299,10 +299,10 @@
        BigDecimal ztRate = chaPrice.multiply(new BigDecimal("100")).divide(zsPrice, 2, 4);
        log.info("当前涨跌幅 = {} % , 涨停幅度 = {} %", Double.valueOf(stock_crease), ztRate);
        if ((new BigDecimal(String.valueOf(stock_crease))).compareTo(ztRate) == 0 && buyType
                .intValue() == 0) {
            return ServerResponse.createByErrorMsg("当前股票已涨停不能买涨");
        }
//        if ((new BigDecimal(String.valueOf(stock_crease))).compareTo(ztRate) == 0 && buyType
//                .intValue() == 0) {
//            return ServerResponse.createByErrorMsg("当前股票已涨停不能买涨");
//        }
        if (stock.getStockPlate() == null || StringUtils.isEmpty(stock.getStockPlate())) {
@@ -388,7 +388,7 @@
        }
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt_autual);
        BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt);
        int compareUserAmtInt = user_enable_amt.compareTo(buy_debit);
        log.info("用户可用金额 = {}  下单扣款(保证金+手续费) =  {}", user_enable_amt, buy_debit);
@@ -479,6 +479,7 @@
        userPosition.setOrderStayDays(Integer.valueOf(0));
        userPosition.setOrderStayFee(new BigDecimal("0"));
        userPosition.setStatus(1);
        this.userPositionMapper.insert(userPosition);
        if (userPosition.getId() != null && userPosition.getId() > 0) {
@@ -496,9 +497,10 @@
    @Override
    public ServerResponse fee(Integer buyNum, BigDecimal nowPrice) {
    public ServerResponse fee(Integer buyNum, BigDecimal nowPrice, Integer lever) {
        int leverValue = (lever == null || lever <= 0) ? 1 : lever;
        BigDecimal buy_amt = nowPrice.multiply(new BigDecimal(buyNum.intValue()));
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt).setScale(2, 4);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFeeByNotional(buy_amt, leverValue).setScale(2, 4);
        return ServerResponse.createBySuccess(buy_fee_amt);
    }
@@ -788,7 +790,7 @@
                    .getBuyMaxAmtPercent().multiply(new BigDecimal("100")) + "%");
        }
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt_autual);
        BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt);
        if (user_enable_amt.compareTo(buy_debit) == -1) {
            return ServerResponse.createByErrorMsg("挂单失败,融资可用金额小于" + buy_debit + "元(含保证金及手续费)");
@@ -950,6 +952,20 @@
    }
    private ServerResponse validateT1BeforeSell(UserPosition userPosition, int doType) {
        if (doType == 0 || userPosition == null || userPosition.getBuyOrderTime() == null) {
            return null;
        }
        String stockGid = userPosition.getStockGid();
        if (stockGid != null && (stockGid.contains("us") || stockGid.contains("hk"))) {
            return null;
        }
        if (!DateTimeUtil.canSellByT1(userPosition.getBuyOrderTime())) {
            return ServerResponse.createByErrorMsg("T+1交易制度,当日买入的股票需下一交易日才能平仓");
        }
        return null;
    }
    public ServerResponse sell(String positionSn, int doType) throws Exception {
        log.info("【用戶交易平倉】 positionSn = {} , dotype = {}", positionSn, Integer.valueOf(doType));
@@ -1028,10 +1044,9 @@
            return ServerResponse.createByErrorMsg("平仓失败,此订单已平仓");
        }
        if (DateTimeUtil.isCanSellOneday(userPosition.getBuyOrderTime(), siteSetting.getCantSellTimes().intValue()) && siteProduct.getTranWithdrawDisplay()) {
            // return ServerResponse.createByErrorMsg(siteSetting.getCantSellTimes() + "分鐘內不能平倉");
            return ServerResponse.createByErrorMsg("当日成交不可平仓");
        ServerResponse t1Check = validateT1BeforeSell(userPosition, doType);
        if (t1Check != null) {
            return t1Check;
        }
        if (1 == userPosition.getIsLock().intValue()) {
@@ -1110,10 +1125,10 @@
        ztRate = ztRate.negate();
        log.info("股票當前漲跌幅 = {} 跌停幅度 = {}", Double.valueOf(stock_crease), ztRate);
        if ((new BigDecimal(String.valueOf(stock_crease))).compareTo(ztRate) == 0 && "買漲"
                .equals(userPosition.getOrderDirection())) {
            return ServerResponse.createByErrorMsg("当前股票已跌停不能卖出");
        }
//        if ((new BigDecimal(String.valueOf(stock_crease))).compareTo(ztRate) == 0 && "買漲"
//                .equals(userPosition.getOrderDirection())) {
//            return ServerResponse.createByErrorMsg("当前股票已跌停不能卖出");
//        }
        Integer buy_num = userPosition.getOrderNum();
@@ -1204,7 +1219,7 @@
        ucd.setUserName(user.getRealName());
        ucd.setDeType("总盈亏");
        ucd.setDeAmt(all_profit);
        ucd.setDeSummary("卖出股票," + userPosition.getStockCode() + "/" + userPosition.getStockName() + ",占用本金:" + freez_amt + ",总手续费:" + all_fee_amt + ",递延费:" + orderStayFee + ",印花稅:" + orderSpread + ",盈亏:" + profitLoss + ",总盈亏:" + all_profit);
        ucd.setDeSummary("卖出股票," + userPosition.getStockCode() + "/" + userPosition.getStockName() + ",占用本金:" + freez_amt + ",总手续费:" + all_fee_amt + ",盈亏:" + profitLoss + ",总盈亏:" + all_profit);
        ucd.setAddTime(new Date());
        ucd.setIsRead(Integer.valueOf(0));
@@ -1299,8 +1314,9 @@
        if (1 == userPosition.getIsLock().intValue()) {
            return ServerResponse.createByErrorMsg("平仓失败 " + userPosition.getLockMsg());
        }
        if (!DateTimeUtil.isCanSell(userPosition.getBuyOrderTime(), siteSetting.getCantSellTimes().intValue())) {
            return ServerResponse.createByErrorMsg("当日成交不可平仓");
        ServerResponse t1Check = validateT1BeforeSell(userPosition, 1);
        if (t1Check != null) {
            return t1Check;
        }
        BigDecimal now_price;
@@ -1364,7 +1380,9 @@
        BigDecimal user_enable_amt = user.getEnableAmt();
        log.info("用戶原本總資金 = {} , 可用 = {}", user_all_amt, user_enable_amt);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(all_buy_amt);
        BigDecimal partialMargin = all_buy_amt.divide(
                new BigDecimal(userPosition.getOrderLever()), 2, RoundingMode.HALF_UP);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(partialMargin);
        log.info("買入手續費 = {}", buy_fee_amt);
        BigDecimal orderSpread = all_buy_amt.multiply(siteSetting.getDutyFee()).setScale(2, 4);
@@ -1921,7 +1939,7 @@
        BigDecimal buy_amt_autual = buy_amt.divide(new BigDecimal(lever.intValue()), 2, 4);
        BigDecimal buy_fee_amt_check = TradeFeeUtil.calcBuyFee(buy_amt);
        BigDecimal buy_fee_amt_check = TradeFeeUtil.calcBuyFee(buy_amt_autual);
        BigDecimal buy_debit_check = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt_check);
        if (user_enable_amt.compareTo(buy_debit_check) < 0) {
            log.info("下单失败,用户可用金额小于{}元(含保证金及手续费)", buy_debit_check);
@@ -1982,8 +2000,8 @@
        userPosition.setOrderStayDays(1);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt).setScale(2, 4);
        log.info("创建模拟持仓 手续费(配资后总资金 * 百分比) = {}", buy_fee_amt);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt_autual).setScale(2, 4);
        log.info("创建模拟持仓 手续费(保证金 * 百分比) = {}", buy_fee_amt);
        userPosition.setOrderFee(buy_fee_amt);
@@ -2026,6 +2044,7 @@
        userPosition.setOrderStayDays(Integer.valueOf(0));
        userPosition.setOrderStayFee(new BigDecimal("0"));
        userPosition.setSpreadRatePrice(new BigDecimal("0"));
        userPosition.setStatus(1);
        this.userPositionMapper.insert(userPosition);
        if (userPosition.getId() == null || userPosition.getId() <= 0) {
@@ -2744,7 +2763,7 @@
        }
        BigDecimal buy_fee_amt_dz = TradeFeeUtil.calcBuyFee(buy_amt);
        BigDecimal buy_fee_amt_dz = TradeFeeUtil.calcBuyFee(buy_amt_autual);
        BigDecimal buy_debit_dz = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt_dz);
        if (user_enable_amt.compareTo(buy_debit_dz) == -1) {
            return ServerResponse.createByErrorMsg("下单失败,融资可用金额小于" + buy_debit_dz + "元(含保证金及手续费)");
@@ -3052,7 +3071,7 @@
        }
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt);
        BigDecimal buy_fee_amt = TradeFeeUtil.calcBuyFee(buy_amt_autual);
        BigDecimal buy_debit = TradeFeeUtil.calcBuyDebit(buy_amt_autual, buy_fee_amt);
        if (user_enable_amt.compareTo(buy_debit) == -1) {
            return ServerResponse.createByErrorMsg("下單失敗,可用金額小於" + buy_debit + "元(含保证金及手续费)");
src/main/java/com/nq/utils/DateTimeUtil.java
@@ -223,6 +223,14 @@
        }
    }
    /** T+1:买入当日不可卖出,下一交易日方可平仓 */
    public static boolean canSellByT1(Date buyDate) {
        if (buyDate == null) {
            return true;
        }
        return !sameDate(getCurrentDate(), buyDate);
    }
    /*日期年月日是否相同*/
    public static boolean sameDate(Date d1, Date d2) {
        SimpleDateFormat fmt = new SimpleDateFormat("yyyyMMdd");
src/main/java/com/nq/utils/TradeFeeUtil.java
New file
@@ -0,0 +1,29 @@
package com.nq.utils;
import java.math.BigDecimal;
import java.math.RoundingMode;
public class TradeFeeUtil {
    public static final BigDecimal BUY_FEE_RATE = new BigDecimal("0.03");
    private TradeFeeUtil() {
    }
    public static BigDecimal calcBuyFee(BigDecimal buyAmt) {
        if (buyAmt == null) {
            return BigDecimal.ZERO;
        }
        return buyAmt.multiply(BUY_FEE_RATE).setScale(2, RoundingMode.HALF_UP);
    }
    public static BigDecimal calcBuyFeeByNotional(BigDecimal notional, Integer lever) {
        return calcBuyFee(notional);
    }
    public static BigDecimal calcBuyDebit(BigDecimal margin, BigDecimal fee) {
        BigDecimal marginAmt = margin == null ? BigDecimal.ZERO : margin;
        BigDecimal feeAmt = fee == null ? BigDecimal.ZERO : fee;
        return marginAmt.add(feeAmt).setScale(2, RoundingMode.HALF_UP);
    }
}
src/main/java/com/nq/utils/pay/OcocnPayUtil.java
New file
@@ -0,0 +1,97 @@
package com.nq.utils.pay;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
public class OcocnPayUtil {
    private OcocnPayUtil() {
    }
    public static String encode(String value) {
        if (value == null) {
            return "";
        }
        try {
            return URLEncoder.encode(value, StandardCharsets.UTF_8.name());
        } catch (UnsupportedEncodingException e) {
            return value;
        }
    }
    public static String buildSubmitSign(String money, String productName, String notifyUrl,
                                         String ordersn, String pid, String returnUrl,
                                         String sitename, String payType, String key) {
        Map<String, String> params = new TreeMap<>();
        params.put("money", money);
        params.put("name", productName);
        params.put("notify_url", notifyUrl);
        params.put("out_trade_no", ordersn);
        params.put("pid", pid);
        params.put("return_url", returnUrl);
        if (StringUtils.isNotBlank(sitename)) {
            params.put("sitename", sitename);
        }
        params.put("type", payType);
        return md5Sign(params, key);
    }
    public static Map<String, String> parseRequestParams(HttpServletRequest request) {
        Map<String, String> result = new HashMap<>();
        if (request == null) {
            return result;
        }
        Map<String, String[]> parameterMap = request.getParameterMap();
        for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
            String[] values = entry.getValue();
            if (values != null && values.length > 0) {
                result.put(entry.getKey(), values[0]);
            }
        }
        return result;
    }
    public static boolean verifyNotifySign(Map<String, String> params, String key) {
        if (params == null || StringUtils.isBlank(key)) {
            return false;
        }
        String remoteSign = params.get("sign");
        if (StringUtils.isBlank(remoteSign)) {
            return false;
        }
        Map<String, String> signParams = new TreeMap<>();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            String name = entry.getKey();
            String value = entry.getValue();
            if ("sign".equalsIgnoreCase(name) || "sign_type".equalsIgnoreCase(name)) {
                continue;
            }
            if (StringUtils.isBlank(value)) {
                continue;
            }
            signParams.put(name, value);
        }
        String localSign = md5Sign(signParams, key);
        return remoteSign.equalsIgnoreCase(localSign);
    }
    private static String md5Sign(Map<String, String> params, String key) {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            if (sb.length() > 0) {
                sb.append('&');
            }
            sb.append(entry.getKey()).append('=').append(entry.getValue());
        }
        sb.append(key);
        return DigestUtils.md5Hex(sb.toString()).toLowerCase();
    }
}
src/main/java/com/nq/vo/pay/OcocnPayVO.java
New file
@@ -0,0 +1,13 @@
package com.nq.vo.pay;
public class OcocnPayVO {
    private String payUrl;
    public String getPayUrl() {
        return payUrl;
    }
    public void setPayUrl(String payUrl) {
        this.payUrl = payUrl;
    }
}
src/main/resources/mapper/UserPositionMapper.xml
@@ -465,7 +465,16 @@
    FROM user_position
    <where>
      user_id = #{uid}
      <if test="state != null">
      <if test="state == 1">
        and sell_order_id is null and (status = 1 or status is null)
      </if>
      <if test="state == 2">
        and status = 2
      </if>
      <if test="state == 0">
        and status = 0
      </if>
      <if test="state != null and state != 0 and state != 1 and state != 2">
        and status = #{state, jdbcType=INTEGER}
      </if>
      <if test="stockCode != null and stockCode != '' ">