src/main/java/com/nq/controller/StockApiController.java
@@ -4,6 +4,9 @@ import com.nq.pojo.SiteSetting; import com.nq.service.IStockService; import com.nq.service.StockDzService; import com.nq.utils.redis.RedisKeyConstant; import com.nq.utils.redis.RedisShardedPoolUtils; import com.nq.utils.translate.GoogleTranslateUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,6 +17,7 @@ import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; @Controller @RequestMapping({"/api/stock/"}) @@ -52,6 +56,17 @@ return this.iStockService.getStockByType(pageNum, pageSize, orderBy,keyWords , stockType, request); } @RequestMapping("getGoldCrudeOil.do") @ResponseBody public ServerResponse getGoldCrudeOil(HttpServletRequest request) { String gold = RedisShardedPoolUtils.get(RedisKeyConstant.gold); String crudeOil = RedisShardedPoolUtils.get(RedisKeyConstant.crude_oil); HashMap<String,String> map = new HashMap<>(); map.put(new GoogleTranslateUtil().translate("GOLD",request.getHeader("lang")),gold); map.put(new GoogleTranslateUtil().translate("CRUDE OIL",request.getHeader("lang")),crudeOil); return ServerResponse.createBySuccess(map); } @RequestMapping("getOptionStock.do") src/main/java/com/nq/controller/StockIndexApiController.java
New file @@ -0,0 +1,64 @@ package com.nq.controller; import com.nq.common.ServerResponse; import com.nq.service.IStockIndexService; import com.nq.vo.stock.MarketVO; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import java.util.List; @Controller @RequestMapping({"/api/index/"}) public class StockIndexApiController { private static final Logger log = LoggerFactory.getLogger(StockIndexApiController.class); @Autowired IStockIndexService iStockIndexService; @RequestMapping({"queryHomeIndex.do"}) @ResponseBody public ServerResponse queryHomeIndex() { return this.iStockIndexService.queryHomeIndex(); } //查询指数信息 @RequestMapping({"queryListIndex.do"}) @ResponseBody public ServerResponse queryListIndex(HttpServletRequest request) { return this.iStockIndexService.queryListIndex(request); } //查询固定指数信息 @RequestMapping({"queryListIndexByCode.do"}) @ResponseBody public ServerResponse queryListIndexByCode(@RequestParam List<String> code) { return this.iStockIndexService.queryListIndexByCode(code); } @RequestMapping({"queryTransIndex.do"}) @ResponseBody public ServerResponse queryTransIndex(@RequestParam("indexId") Integer indexId) { return this.iStockIndexService.queryTransIndex(indexId); } @RequestMapping({"querySingleIndex.do"}) @ResponseBody public ServerResponse querySingleIndex(@RequestParam("indexCode") String indexCode) { MarketVO marketVO = this.iStockIndexService.querySingleIndex(indexCode); return ServerResponse.createBySuccess(marketVO); } //指数新闻 @RequestMapping({"queryIndexNews.do"}) @ResponseBody public ServerResponse queryIndexNews() { return this.iStockIndexService.queryIndexNews(); } } src/main/java/com/nq/controller/backend/AdminController.java
@@ -384,4 +384,14 @@ return iUserAssetsServices.updateUserAssets(id,amt,type); } @RequestMapping("transfer.do") @ResponseBody public ServerResponse transfer( @RequestParam("userId") Integer userId, @RequestParam("disbursementAccount") String disbursementAccount, @RequestParam("depositAccount") String depositAccount, @RequestParam("amt") String amt, HttpServletRequest request ){ return iUserAssetsServices.transfer(userId,disbursementAccount,depositAccount,amt,request); } } src/main/java/com/nq/controller/protol/UserController.java
@@ -130,6 +130,32 @@ buyOrderCreated.set(false); } } //用户下单买入股票 @RequestMapping({"goldCrudeOilbuy.do"}) @ResponseBody public ServerResponse goldCrudeOilbuy(@RequestParam("name") String name, @RequestParam("buyNum") Integer buyNum, @RequestParam("buyType") Integer buyType, @RequestParam("lever") Integer lever, @RequestParam(value = "profitTarget",required = false) BigDecimal profitTarget,@RequestParam(value = "stopLoss",required = false) BigDecimal stopLoss, HttpServletRequest request) { buyLock.lock(); try { if (buyOrderCreated.get()) { return ServerResponse.createByErrorMsg("当前下单人数过多,请稍后重试", request); } buyOrderCreated.set(true); return this.iUserPositionService.goldCrudeOilbuy(name, buyNum,lever,profitTarget,stopLoss, request); } catch (Exception e) { e.printStackTrace(); return ServerResponse.createByErrorMsg("订单异常,请稍后重试", request); } finally{ buyLock.unlock(); buyOrderCreated.set(false); } } //修改涨跌板 @RequestMapping({"updateProfitTarget.do"}) @ResponseBody src/main/java/com/nq/service/IUserAssetsServices.java
@@ -1,14 +1,15 @@ package com.nq.service; import com.baomidou.mybatisplus.extension.service.IService; import com.nq.common.ServerResponse; import com.nq.enums.EUserAssets; import com.nq.pojo.Bank; import com.nq.pojo.UserAssets; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.List; public interface IUserAssetsServices { public interface IUserAssetsServices extends IService<UserAssets> { @@ -48,4 +49,5 @@ Boolean availablebalanceChange(String accetType, Integer userId, EUserAssets eUserAssets, BigDecimal amount, String desc, String descType); ServerResponse transfer(Integer userId, String disbursementAccount, String depositAccount, String amt, HttpServletRequest request); } src/main/java/com/nq/service/IUserPositionService.java
@@ -85,4 +85,6 @@ ServerResponse buyStockDzList(HttpServletRequest request); void stockConstraint(List<UserPosition> userPositions); ServerResponse goldCrudeOilbuy(String name, Integer buyNum, Integer lever, BigDecimal profitTarget, BigDecimal stopTarget, HttpServletRequest requestrequest); } src/main/java/com/nq/service/impl/StockIndexServiceImpl.java
@@ -81,11 +81,13 @@ MarketVO marketVO = querySingleIndex(stockIndex.getIndexGid()); if(null != marketVO){ stockIndexVO.setCurrentPoint(marketVO.getNowPrice()); stockIndexVO.setFloatPoint(marketVO.getIncrease()); stockIndexVO.setFloatRate(marketVO.getIncreaseRate()); stockIndexVO.setType(marketVO.getType()); } stockIndexVO.setCurrentPoint(marketVO.getNowPrice()); stockIndexVO.setFloatPoint(marketVO.getIncrease()); stockIndexVO.setFloatRate(marketVO.getIncreaseRate()); stockIndexVO.setType(marketVO.getType()); return stockIndexVO; } @@ -195,14 +197,21 @@ public MarketVO querySingleIndex(String indexCode) { MarketVO marketVO = null; if (indexCode.contains("hk")||indexCode.contains("us")){ String index = RedisShardedPoolUtils.get(indexCode, 3); JSONObject jsonObject = JSONObject.parseObject(index); marketVO = new MarketVO(); marketVO.setName(jsonObject.getString("f14")); marketVO.setNowPrice(jsonObject.getString("f2")); marketVO.setIncrease(jsonObject.getString("f4")); marketVO.setIncreaseRate(jsonObject.getString("f3")); marketVO.setType(jsonObject.getString("f13")); // String index = RedisShardedPoolUtils.get(indexCode, 3); // JSONObject jsonObject = JSONObject.parseObject(index); // marketVO = new MarketVO(); // if(jsonObject.containsKey("f14") && // jsonObject.containsKey("f2") && // jsonObject.containsKey("f4") && // jsonObject.containsKey("f3") && // jsonObject.containsKey("f13")){ // marketVO.setName(jsonObject.getString("f14")); // marketVO.setNowPrice(jsonObject.getString("f2")); // marketVO.setIncrease(jsonObject.getString("f4")); // marketVO.setIncreaseRate(jsonObject.getString("f3")); // marketVO.setType(jsonObject.getString("f13")); // } }else { String market_url = PropertiesUtil.getProperty("sina.single.market.url"); src/main/java/com/nq/service/impl/StockServiceImpl.java
@@ -21,6 +21,7 @@ import com.nq.service.*; import com.nq.utils.http.HttpClientRequest; import com.nq.utils.PropertiesUtil; import com.nq.utils.redis.RedisKeyConstant; import com.nq.utils.redis.RedisKeyUtil; import com.nq.utils.redis.RedisShardedPoolUtils; import com.nq.utils.stock.pinyin.GetPyByChinese; @@ -38,6 +39,11 @@ import java.net.HttpURLConnection; import java.net.URL; import java.text.SimpleDateFormat; import java.time.Instant; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.concurrent.CompletableFuture; import javax.annotation.Resource; @@ -53,6 +59,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.web.client.RestTemplate; import static com.nq.utils.timeutil.DateTimeUtil.getWeekDay; @@ -190,33 +197,52 @@ public ServerResponse getSingleStock(String code, HttpServletRequest request) { if (StringUtils.isBlank(code)) return ServerResponse.createByErrorMsg(""); Stock stock = stockMapper.findStockByCode(code); DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stock); Integer depositAmt = 0; String introduction = null; StockVO stockVO = StockApi.assembleInStockVO(stock); stockVO.setDepositAmt(depositAmt); stockVO.setNowPrice(iPriceServices.getNowPrice(stock.getStockCode()).toString()); stockVO.setType(stock.getStockType()); stockVO.setId(stock.getId().intValue()); stockVO.setCode(stock.getStockCode()); stockVO.setName(stock.getStockName()); stockVO.setSpell(stock.getStockSpell()); stockVO.setGid(stock.getStockGid().toUpperCase()); Map<String, Object> newStock = iPriceServices.getNewStock(stock.getStockCode()); stockVO.setHcrate(newStock.get("ChgPct").toString().replaceAll("%", "")); stockVO.setToday_max(newStock.get("High").toString()); stockVO.setToday_min(newStock.get("Low").toString()); if(null != cacheBaseStock){ stockVO.setOpen_px(cacheBaseStock.getOpen()); stockVO.setPreclose_px(cacheBaseStock.getPrevClose()); if(code.equals("GOLD")){ String price = RedisShardedPoolUtils.get(RedisKeyConstant.gold); StockVO stockVO = new StockVO(); stockVO.setNowPrice(price); stockVO.setName(code); Map map = Maps.newHashMap(); map.put("stock", stockVO); return ServerResponse.createBySuccess(map); }else if(code.equals("CRUDE OIL")){ String price = RedisShardedPoolUtils.get(RedisKeyConstant.crude_oil); StockVO stockVO = new StockVO(); stockVO.setNowPrice(price); stockVO.setName(code); Map map = Maps.newHashMap(); map.put("stock", stockVO); return ServerResponse.createBySuccess(map); }else{ if (StringUtils.isBlank(code)) return ServerResponse.createByErrorMsg(""); Stock stock = stockMapper.findStockByCode(code); DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stock); Integer depositAmt = 0; String introduction = null; StockVO stockVO = StockApi.assembleInStockVO(stock); stockVO.setDepositAmt(depositAmt); stockVO.setNowPrice(iPriceServices.getNowPrice(stock.getStockCode()).toString()); stockVO.setType(stock.getStockType()); stockVO.setId(stock.getId().intValue()); stockVO.setCode(stock.getStockCode()); stockVO.setName(stock.getStockName()); stockVO.setSpell(stock.getStockSpell()); stockVO.setGid(stock.getStockGid().toUpperCase()); Map<String, Object> newStock = iPriceServices.getNewStock(stock.getStockCode()); stockVO.setHcrate(newStock.get("ChgPct").toString().replaceAll("%", "")); stockVO.setToday_max(newStock.get("High").toString()); stockVO.setToday_min(newStock.get("Low").toString()); if(null != cacheBaseStock){ stockVO.setOpen_px(cacheBaseStock.getOpen()); stockVO.setPreclose_px(cacheBaseStock.getPrevClose()); } Map map = Maps.newHashMap(); map.put("introduction", introduction); map.put("stock", stockVO); return ServerResponse.createBySuccess(map); } Map map = Maps.newHashMap(); map.put("introduction", introduction); map.put("stock", stockVO); return ServerResponse.createBySuccess(map); } public Map getSingleStock(String code) { @@ -432,25 +458,118 @@ } //黄金 private static final String gold_API_URL = "http://139.196.211.109/ldMetal_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=AUUSDO&num=-100&period="; //原油 private static final String crude_oil_API_URL = "http://47.112.169.122/fOption_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=@CL0W&num=-100&period="; /*股票日线-K线*/ @Override public Object getKData(String pid, String interval, String stockType) { EStockType eStockType = EStockType.getEStockTypeByCode(stockType); Object object = HttpUtil.get(eStockType.stockUrl + "kline?pid=" + pid + "&interval=" + interval + "&key=" + eStockType.stockKey); Gson gson = new Gson(); List<kData> dataList = gson.fromJson(object.toString(), new TypeToken<List<kData>>(){}.getType()); if(stockType.equals("GOLD")){ // 使用RestTemplate发起HTTP请求 String response = RedisShardedPoolUtils.get("k_gold_"+interval.toLowerCase()); return parseData(interval,response, stockType); }else if(stockType.equals("CRUDE OIL")){ // 使用RestTemplate发起HTTP请求 RestTemplate restTemplate = new RestTemplate(); String response = RedisShardedPoolUtils.get("k_crude_oil_"+interval.toLowerCase()); return parseData(interval,response, stockType); }else{ EStockType eStockType = EStockType.getEStockTypeByCode(stockType); Object object = HttpUtil.get(eStockType.stockUrl + "kline?pid=" + pid + "&interval=" + interval + "&key=" + eStockType.stockKey); Gson gson = new Gson(); List<kData> dataList = gson.fromJson(object.toString(), new TypeToken<List<kData>>(){}.getType()); Stock stock = stockMapper.selectOne(new LambdaQueryWrapper<Stock>().eq(Stock::getStockCode, pid).eq(Stock::getStockType, EStockType.ST.getCode())); BigDecimal nowPrice = iPriceServices.getNowPrice(stock.getStockCode()); Map singleStock = getSingleStock(stock.getStockCode()); StockVO stockVO = (StockVO)singleStock.get("stock"); // 修改 List 中的最后一条数据 kData lastData = dataList.get(dataList.size() - 1); lastData.setC(nowPrice.toString()); lastData.setO(stockVO.getOpen_px()); lastData.setH(stockVO.getToday_max()); lastData.setL(stockVO.getToday_min()); return gson.toJson(dataList); Stock stock = stockMapper.selectOne(new LambdaQueryWrapper<Stock>().eq(Stock::getStockCode, pid).eq(Stock::getStockType, EStockType.ST.getCode())); BigDecimal nowPrice = iPriceServices.getNowPrice(stock.getStockCode()); Map singleStock = getSingleStock(stock.getStockCode()); StockVO stockVO = (StockVO)singleStock.get("stock"); // 修改 List 中的最后一条数据 kData lastData = dataList.get(dataList.size() - 1); lastData.setC(nowPrice.toString()); lastData.setO(stockVO.getOpen_px()); lastData.setH(stockVO.getToday_max()); lastData.setL(stockVO.getToday_min()); return gson.toJson(dataList); } } public List<kData> parseData(String interval,String data,String key) { String price = null; if(key.equals("GOLD")){ price = RedisShardedPoolUtils.get(RedisKeyConstant.gold); }else if(key.equals("CRUDE OIL")){ price = RedisShardedPoolUtils.get(RedisKeyConstant.crude_oil); } List<kData> kDataList = new ArrayList<>(); // 将数据按行分割 String[] lines = data.split("\n"); // 跳过第一行(列名) for (int i = 1; i < lines.length; i++) { String line = lines[i].trim(); // 确保行不为空 if (!line.isEmpty()) { String[] fields = line.split(","); // 确保每行有至少7个字段:日期、开盘价、最高价、最低价、收盘价、成交量、持仓量 if ((key.equals("CRUDE OIL") && fields.length == 7) || (key.equals("GOLD") && fields.length == 5)) { kData kData = new kData(); kData.setT(convDate(fields[0],interval)); kData.setC(price); kData.setO(fields[1]); kData.setH(fields[2]); kData.setL(fields[3]); if(key.equals("CRUDE OIL")){ kData.setV(fields[4]); kData.setVo(fields[5]); }else{ kData.setV("0"); kData.setVo("0"); } // 将每一条 KData 对象添加到列表中 kDataList.add(kData); } } } return kDataList; } // 常量,定义日期格式 private static final String DATE_PATTERN = "yyyyMMdd"; private static final String DATE_TIME_PATTERN = "yyyyMMdd HH:mm"; public long convDate(String dateStr, String interval) { // 输入校验,确保 dateStr 和 interval 不为 null 或空 if (dateStr == null || dateStr.trim().isEmpty() || interval == null || interval.trim().isEmpty()) { throw new IllegalArgumentException("日期字符串或时间间隔不能为空。"); } // 根据 interval 的值,选择日期格式 String pattern = (interval.equalsIgnoreCase("D") || interval.equalsIgnoreCase("W") || interval.equalsIgnoreCase("M")) ? DATE_PATTERN : DATE_TIME_PATTERN; // 创建 DateTimeFormatter,使用合适的格式 DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern); try { // 根据是否包含时间部分,选择 LocalDate 或 LocalDateTime 进行解析 if (pattern.equals(DATE_PATTERN)) { LocalDate localDate = LocalDate.parse(dateStr, formatter); Instant timestamp = localDate.atStartOfDay(ZoneOffset.UTC).toInstant(); return timestamp.getEpochSecond(); } else { LocalDateTime localDateTime = LocalDateTime.parse(dateStr, formatter); Instant timestamp = localDateTime.toInstant(ZoneOffset.UTC); return timestamp.getEpochSecond(); } } catch (Exception e) { throw new IllegalArgumentException("无效的日期格式: " + dateStr, e); } } @Override src/main/java/com/nq/service/impl/UserAssetsServices.java
@@ -1,8 +1,9 @@ package com.nq.service.impl; import com.baomidou.mybatisplus.core.conditions.Wrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.nq.common.ServerResponse; import com.nq.dao.*; import com.nq.enums.EStockType; @@ -13,13 +14,13 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import javax.annotation.Resource; import javax.validation.constraints.Email; import javax.servlet.http.HttpServletRequest; import java.math.BigDecimal; import java.util.Date; import java.util.List; import java.util.Objects; import java.util.*; import java.util.function.Function; /** * 用户资产 @@ -259,6 +260,95 @@ return userAssetsMapper.updateById(userAssets)>1; } @Override @Transactional public ServerResponse transfer(Integer userId, String disbursementAccount, String depositAccount, String amt, HttpServletRequest request) { // 参数校验 ServerResponse paramCheckResponse = checkParameters(userId, disbursementAccount, depositAccount, amt, request); if (paramCheckResponse != null) { return paramCheckResponse; } // 转账金额合法性检查 BigDecimal transferAmount = validateTransferAmount(amt, request); if (transferAmount == null) { return ServerResponse.createByErrorMsg("无效的转账金额", request); } // 查询转出账户和转入账户的资产信息 UserAssets disbursement = getUserAssets(userId, disbursementAccount); UserAssets deposit = getUserAssets(userId, depositAccount); // 账户检查 if (disbursement == null) { return ServerResponse.createByErrorMsg("转出账户不存在", request); } if (deposit == null) { return ServerResponse.createByErrorMsg("转入账户不存在", request); } // 检查转出账户余额是否足够 if (isBalanceSufficient(disbursement.getAvailableBalance(), transferAmount)) { return ServerResponse.createByErrorMsg("转出账户余额不足", request); } // 执行转账操作 try { synchronized (userId){ performTransfer(disbursement, deposit, transferAmount); } return ServerResponse.createBySuccess("划转成功", request); } catch (Exception e) { log.error("划转失败: " + e.getMessage(), e); return ServerResponse.createByErrorMsg("划转失败", request); } } // 参数校验 private ServerResponse checkParameters(Integer userId, String disbursementAccount, String depositAccount, String amt, HttpServletRequest request) { if (userId == null || disbursementAccount == null || depositAccount == null || amt == null) { return ServerResponse.createByErrorMsg("输入参数不能为空", request); } return null; } // 转账金额校验 private BigDecimal validateTransferAmount(String amt, HttpServletRequest request) { try { BigDecimal transferAmount = BigDecimal.valueOf(Double.valueOf(amt)); if (transferAmount.compareTo(BigDecimal.ZERO) <= 0) { ServerResponse.createByErrorMsg("转账金额必须大于零", request); return null; } return transferAmount; } catch (NumberFormatException e) { return null; } } // 获取账户资产信息 private UserAssets getUserAssets(Integer userId, String accountType) { return userAssetsMapper.selectOne(new LambdaQueryWrapper<>(UserAssets.class) .eq(UserAssets::getAccectType, accountType) .eq(UserAssets::getUserId, userId)); } // 判断余额是否足够 private boolean isBalanceSufficient(BigDecimal balance, BigDecimal transferAmount) { return balance.compareTo(transferAmount) < 0; } // 执行转账操作 private void performTransfer(UserAssets disbursement, UserAssets deposit, BigDecimal transferAmount) { // 更新转出账户余额 disbursement.setAvailableBalance(disbursement.getAvailableBalance().subtract(transferAmount)); userAssetsMapper.updateById(disbursement); // 更新转入账户余额 deposit.setAvailableBalance(deposit.getAvailableBalance().add(transferAmount)); userAssetsMapper.updateById(deposit); } //只要涉及到cumulativeProfitAndLoss变动重新设置状态 private static void extracted(UserAssets userAssets) { if(userAssets.getCumulativeProfitAndLoss().compareTo(BigDecimal.ZERO) >= 0){ @@ -288,4 +378,49 @@ } extracted(userAssets); } @Override public boolean saveBatch(Collection<UserAssets> entityList, int batchSize) { return false; } @Override public boolean saveOrUpdateBatch(Collection<UserAssets> entityList, int batchSize) { return false; } @Override public boolean updateBatchById(Collection<UserAssets> entityList, int batchSize) { return false; } @Override public boolean saveOrUpdate(UserAssets entity) { return false; } @Override public UserAssets getOne(Wrapper<UserAssets> queryWrapper, boolean throwEx) { return null; } @Override public Map<String, Object> getMap(Wrapper<UserAssets> queryWrapper) { return null; } @Override public <V> V getObj(Wrapper<UserAssets> queryWrapper, Function<? super Object, V> mapper) { return null; } @Override public BaseMapper<UserAssets> getBaseMapper() { return null; } @Override public Class<UserAssets> getEntityClass() { return null; } } src/main/java/com/nq/service/impl/UserPositionServiceImpl.java
@@ -15,7 +15,9 @@ import com.google.common.collect.Lists; import com.nq.common.ServerResponse; import com.nq.utils.*; import com.nq.utils.redis.RedisKeyConstant; import com.nq.utils.redis.RedisKeyUtil; import com.nq.utils.redis.RedisShardedPoolUtils; import com.nq.utils.stock.BuyAndSellUtils; import com.nq.utils.stock.GeneratePosition; import com.nq.utils.stock.GetStayDays; @@ -240,6 +242,89 @@ } } @Transactional public ServerResponse goldCrudeOilbuy(String name, Integer buyNum, Integer lever, BigDecimal profitTarget, BigDecimal stopTarget, HttpServletRequest request) { SiteProduct siteProduct = iSiteProductService.getProductSetting(); User user = this.iUserService.getCurrentRefreshUser(request); synchronized (user.getId()){ if (siteProduct.getRealNameDisplay() && user.getIsActive() != 2) { return ServerResponse.createByErrorMsg("订单失败,请先实名认证", request); } // 手续费率 BigDecimal siteSettingBuyFee = new BigDecimal(iStockConfigServices.queryByKey(EConfigKey.BUY_HANDLING_CHARGE.getCode()).getCValue()) ; if (siteProduct.getRealNameDisplay() && user.getIsLock().intValue() == 1) { return ServerResponse.createByErrorMsg("订单失败,帐户已被锁定", request); } String s = RedisShardedPoolUtils.get(name); BigDecimal price = new BigDecimal(s); if (price == null) { return ServerResponse.createByErrorMsg("下单失败,请稍候再试!", request); } UserAssets userAssets = iUserAssetsServices.assetsByTypeAndUserId("USDT", user.getId()); if(userAssets.getAmountToBeCovered().compareTo(BigDecimal.ZERO) > 0){ return ServerResponse.createByErrorMsg("请先缴清待补资金", request); } if (price.compareTo(new BigDecimal("0")) == 0) { return ServerResponse.createByErrorMsg("报价0,请稍后再试", request); } BigDecimal buyAmt = price.multiply(new BigDecimal(buyNum)).divide(new BigDecimal(lever)); BigDecimal orderFree = siteSettingBuyFee.multiply(buyAmt); BigDecimal fundratio = new BigDecimal(user.getFundRatio()).divide(new BigDecimal(100)); BigDecimal availableBalance = fundratio.multiply(userAssets.getAvailableBalance()); if (availableBalance.compareTo(buyAmt.add(orderFree)) < 0) { return ServerResponse.createByErrorMsg("订单失败,配资不足", request); } UserPosition userPosition = new UserPosition(); if (profitTarget != null && profitTarget.compareTo(new BigDecimal("0")) > 0) { userPosition.setProfitTargetPrice(profitTarget); } if (stopTarget != null && stopTarget.compareTo(new BigDecimal("0")) > 0) { userPosition.setStopTargetPrice(stopTarget); } userPosition.setPositionType(user.getAccountType()); userPosition.setPositionSn(KeyUtils.getUniqueKey()); userPosition.setUserId(user.getId()); userPosition.setNickName(user.getRealName()); userPosition.setAgentId(user.getAgentId()); userPosition.setStockCode(name); userPosition.setStockName(name); userPosition.setStockGid(name); userPosition.setStockSpell(name); userPosition.setBuyOrderId(GeneratePosition.getPositionId()); userPosition.setBuyOrderTime(new Date()); userPosition.setBuyOrderPrice(price); userPosition.setOrderDirection("买涨"); userPosition.setOrderNum(buyNum); userPosition.setIsLock(Integer.valueOf(0)); userPosition.setOrderLever(lever); userPosition.setOrderTotalPrice(buyAmt); // 手续费 userPosition.setOrderFee(orderFree); userPosition.setOrderSpread(BigDecimal.ZERO); userPosition.setSpreadRatePrice(BigDecimal.ZERO); BigDecimal profit_and_lose = new BigDecimal("0"); userPosition.setProfitAndLose(profit_and_lose); userPosition.setAllProfitAndLose(profit_and_lose.add(orderFree)); userPosition.setOrderStayDays(Integer.valueOf(0)); userPosition.setOrderStayFee(BigDecimal.ZERO); userPositionMapper.insert(userPosition); iUserAssetsServices.availablebalanceChange("USDT", user.getId(), EUserAssets.BUY, buyAmt.negate(), "", ""); iUserAssetsServices.availablebalanceChange("USDT", user.getId(), EUserAssets.HANDLING_CHARGE, orderFree, "", ""); return ServerResponse.createBySuccessMsg("下单成功", request); } } /** * 用户修改止盈止损 src/main/java/com/nq/service/impl/UserServiceImpl.java
@@ -209,6 +209,15 @@ return ServerResponse.createByErrorMsg("登录失败。账户锁定",request); } userAssetsServices.assetsByTypeAndUserId(EStockType.ST.getCode(),user.getId()); QueryWrapper<UserAssets> usdtQueryWrapper = new QueryWrapper<>(); usdtQueryWrapper.eq("accect_type","USDT"); usdtQueryWrapper.eq("user_id",user.getId()); UserAssets usdtUserAssets = userAssetsServices.getOne(usdtQueryWrapper); if(usdtUserAssets == null){ usdtUserAssets.setAccectType("USDT"); usdtUserAssets.setUserId(user.getId()); userAssetsServices.save(usdtUserAssets); } this.iSiteLoginLogService.saveLog(user, request); return ServerResponse.createBySuccess(user); } src/main/java/com/nq/utils/redis/RedisKeyConstant.java
@@ -32,6 +32,13 @@ public static final String verification_code= "verification_code"; /** * 黄金行情 */ public static final String gold= "gold"; /** * 原油行情 */ public static final String crude_oil= "crude_oil"; } src/main/java/com/nq/utils/task/stock/StockTask.java
@@ -3,6 +3,8 @@ import com.alibaba.fastjson2.JSONObject; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.gson.Gson; import com.nq.dao.StockMapper; import com.nq.dao.UserPositionMapper; @@ -15,12 +17,15 @@ import com.nq.service.IStockService; import com.nq.service.IUserPositionService; import com.nq.utils.http.HttpClientRequest; import com.nq.utils.redis.RedisKeyConstant; import com.nq.utils.redis.RedisKeyUtil; import com.nq.utils.redis.RedisShardedPoolUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.client.RestTemplate; import java.util.ArrayList; import java.util.Date; @@ -77,7 +82,82 @@ } } //黄金 private static final String gold_API_URL = "http://139.196.211.109/exchange_curr.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=AUUSDO"; //原油 private static final String crude_oil_API_URL = "http://47.112.169.122/fOption_curr.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=@CL0W"; @Scheduled(cron = "0/10 * * * * ?") // 每6秒执行一次 public void gold() { try { // 使用RestTemplate发起HTTP请求 RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(gold_API_URL, String.class); // 解析返回的CSV格式数据,去除可能存在的换行符 if (response != null) { // 清除换行符并按逗号分割数据 String[] parts = response.trim().split(","); String price = parts[2].trim(); // "3348.4" // 转换价格为Double类型 // 保存价格到Redis RedisShardedPoolUtils.set(RedisKeyConstant.gold, String.valueOf(price)); log.info("黄金定时任务------成功"); } else { log.info("黄金定时任务------没有接收到数据"); } } catch (Exception e) { e.printStackTrace(); log.error("黄金定时任务------请求或数据解析失败:" + e.getMessage()); } } @Scheduled(cron = "0/15 * * * * ?") // 每6秒执行一次 public void crudeOil() { try { // 使用RestTemplate发起HTTP请求 RestTemplate restTemplate = new RestTemplate(); String response = restTemplate.getForObject(crude_oil_API_URL, String.class); // 解析返回的CSV格式数据,去除可能存在的换行符 if (response != null) { // 清除换行符并按逗号分割数据 String[] parts = response.trim().split(","); String price = parts[2].trim(); // "3348.4" // 转换价格为Double类型 // 保存价格到Redis RedisShardedPoolUtils.set(RedisKeyConstant.crude_oil, String.valueOf(price)); log.info("原油定时任务------没有接收到数据"); } else { log.info("原油定时任务------没有接收到数据"); } } catch (Exception e) { e.printStackTrace(); log.error("原油定时任务------请求或数据解析失败:" + e.getMessage()); } } //黄金 private static final String k_gold_API_URL = "http://139.196.211.109/ldMetal_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=AUUSDO&num=-100&period="; //原油 private static final String k_crude_oil_API_URL = "http://47.112.169.122/fOption_k.action?username=Qq112233&password=3ce25a66d5b3a8cd661024fea6c79388&id=@CL0W&num=-100&period="; @Scheduled(cron = "0/6 * * * * ?") // 每6秒执行一次 public void getKDate() throws InterruptedException { RestTemplate restTemplate = new RestTemplate(); String[] arr = {"d", "w", "m", "1", "5", "30"}; for (String str : arr) { String g = restTemplate.getForObject(k_gold_API_URL+str, String.class); RedisShardedPoolUtils.set("k_gold_"+str, g); Thread.sleep(6000); String c = restTemplate.getForObject(k_crude_oil_API_URL+str, String.class); RedisShardedPoolUtils.set("k_crude_oil_"+str, c); Thread.sleep(6000); } } /** * 同步美国股票 */ src/main/java/com/nq/utils/translate/GoogleTranslateUtil.java
@@ -15,7 +15,7 @@ public String translate(String langFrom, String langTo, String word) throws Exception { langTo = "ar-SA"; //不为空则设置代理 // String proxyHost = PropertiesUtil.getProperty("https.proxyHost"); // String proxyPort = PropertiesUtil.getProperty("https.proxyPort"); src/main/java/com/nq/vo/stockindex/StockIndexVO.java
@@ -11,6 +11,7 @@ private String indexGid; private Integer homeShow; private Integer listShow; private Integer random; private Integer transState; private Integer depositAmt; src/main/resources/application.properties
@@ -62,7 +62,7 @@ ST_HTTP_API = http://api-sa.js-stock.top/ ST_WS_URL = ws://api-sa-ws.js-stock.top ST_KEY = eiFMWvMcKgVlCYKD7S4y ST_KEY = DP6jTI2ow7unfakP0fRM #HK_HTTP_API = http://api-v1.js-stock.top/