| .idea/A-stock.iml | ●●●●● patch | view | raw | blame | history | |
| .idea/git_toolbox_prj.xml | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/controller/protol/UserController.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/service/IUserPositionService.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/service/impl/UserPositionServiceImpl.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/utils/DateTimeUtil.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/utils/TradeFeeUtil.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/utils/pay/OcocnPayUtil.java | ●●●●● patch | view | raw | blame | history | |
| src/main/java/com/nq/vo/pay/OcocnPayVO.java | ●●●●● patch | view | raw | blame | history | |
| src/main/resources/mapper/UserPositionMapper.xml | ●●●●● 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 != '' ">