| | |
| | | package com.nq.service.impl; |
| | | |
| | | import cn.hutool.core.date.DateTime; |
| | | import cn.hutool.core.date.DateUtil; |
| | | import cn.hutool.http.HttpUtil; |
| | | import com.alibaba.fastjson2.JSONArray; |
| | | import com.alibaba.fastjson2.JSONObject; |
| | | import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; |
| | | import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; |
| | | import com.github.pagehelper.PageHelper; |
| | |
| | | import com.google.gson.reflect.TypeToken; |
| | | import com.nq.common.ServerResponse; |
| | | import com.nq.dao.*; |
| | | import com.nq.enums.EConfigKey; |
| | | import com.nq.enums.EStockType; |
| | | import com.nq.pojo.*; |
| | | import com.nq.pojo.reponse.RPageInfo; |
| | | import com.nq.service.*; |
| | | import com.nq.utils.http.HttpClientRequest; |
| | | import com.nq.utils.PropertiesUtil; |
| | | import com.nq.utils.http.HttpRequest; |
| | | import com.nq.utils.redis.RedisKeyUtil; |
| | | import com.nq.utils.redis.RedisShardedPoolUtils; |
| | | import com.nq.utils.stock.pinyin.GetPyByChinese; |
| | | import com.nq.utils.stock.qq.QqStockApi; |
| | | import com.nq.utils.stock.sina.StockApi; |
| | | import com.nq.vo.stock.*; |
| | | import com.nq.vo.stock.ai.StockAiOrderVO; |
| | | import com.nq.vo.stock.k.MinDataVO; |
| | | import com.nq.vo.stock.k.echarts.EchartsDataVO; |
| | | |
| | | import java.lang.reflect.Type; |
| | | import java.math.BigDecimal; |
| | | import java.math.RoundingMode; |
| | | import java.util.*; |
| | | import java.util.function.Function; |
| | | import java.util.stream.Collectors; |
| | | import javax.annotation.Resource; |
| | | import javax.servlet.http.HttpServletRequest; |
| | | import javax.servlet.http.HttpServletResponse; |
| | | |
| | | import lombok.Data; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | |
| | | @Autowired |
| | | SiteNewsMapper siteNewsMapper; |
| | | |
| | | @Autowired |
| | | StockConfigMapper stockConfigMapper; |
| | | |
| | | @Resource |
| | | StockSettingMapper stockSettingMapper; |
| | | |
| | | public ServerResponse getMarket() { |
| | | String market_url = PropertiesUtil.getProperty("sina.market.url"); |
| | |
| | | Integer depositAmt = 0; |
| | | String introduction = null; |
| | | String result = null; |
| | | com.alibaba.fastjson2.JSONObject json = null; |
| | | JSONObject json = null; |
| | | //期货 |
| | | String url = null; |
| | | if (code.contains("sh") || code.contains("sz")) { //指数 |
| | |
| | | if (result.contains("msg")) { |
| | | introduction = "暂无数据"; |
| | | } else { |
| | | json = com.alibaba.fastjson2.JSONObject.parseObject(result); |
| | | json = JSONObject.parseObject(result); |
| | | if (json.getJSONObject("data").getJSONArray("gszl").size() > 0) { |
| | | introduction = json.getJSONObject("data").getJSONArray("gszl").getJSONObject(0).getString("COMPPROFILE"); |
| | | } else { |
| | |
| | | * 105.UCL&ut=fa5fd1943c7b386f172d6893dbfba10b&wbp2u=%7C0%7C0%7C0%7Cweb&_=时间戳 |
| | | */ |
| | | long now = System.currentTimeMillis(); |
| | | com.alibaba.fastjson2.JSONObject buyjson = null; |
| | | JSONObject buyjson = null; |
| | | String buyresult = null; |
| | | try { |
| | | String buyurl = PropertiesUtil.getProperty("us.stock.buy.url") + stockVO.getType() + "." + stock.getStockCode() + "&ut=fa5fd1943c7b386f172d6893dbfba10b&wbp2u=%7C0%7C0%7C0%7Cweb&_=" + now; |
| | | buyresult = HttpClientRequest.doGet(buyurl); |
| | | buyjson = com.alibaba.fastjson2.JSONObject.parseObject(buyresult); |
| | | buyjson = JSONObject.parseObject(buyresult); |
| | | } catch (Exception e) { |
| | | log.error("获取分时交易数据失败", e); |
| | | buyjson.put("data", "暂无数据"); |
| | |
| | | EchartsDataVO echartsDataVO = StockApi.assembleEchartsDataVO(minDataVO); |
| | | return ServerResponse.createBySuccess(echartsDataVO); |
| | | } |
| | | @lombok.Data |
| | | @Data |
| | | class kData { |
| | | long t; |
| | | String c; |
| | |
| | | // stockListVO.setNowPrice(stockListVO.getNowPrice()); |
| | | // } |
| | | // } |
| | | |
| | | stockAdminListVO.setNowPrice(stockListVO.getNowPrice()); |
| | | stockAdminListVO.setHcrate(stockListVO.getHcrate()); |
| | | if (stockListVO != null) { |
| | | stockAdminListVO.setNowPrice(stockListVO.getNowPrice()); |
| | | stockAdminListVO.setHcrate(stockListVO.getHcrate()); |
| | | } |
| | | stockAdminListVO.setSpreadRate(stock.getSpreadRate()); |
| | | ServerResponse serverResponse = selectRateByDaysAndStockCode(stock.getStockCode(), 3); |
| | | BigDecimal day3Rate = new BigDecimal("0"); |
| | |
| | | log.info("涨停板接口:{}", url); |
| | | String res = HttpClientRequest.doGet(url); |
| | | |
| | | com.alibaba.fastjson2.JSONObject json = com.alibaba.fastjson2.JSONObject.parseObject(res); |
| | | com.alibaba.fastjson2.JSONArray pool = null; |
| | | JSONObject json = JSONObject.parseObject(res); |
| | | JSONArray pool = null; |
| | | if (json.getJSONObject("data") != null) { |
| | | pool = json.getJSONObject("data").getJSONArray("pool"); |
| | | } |
| | |
| | | url = url.replace("20221202", day1) + time; |
| | | // log.info("涨停板接口:{}",url); |
| | | String res = HttpClientRequest.doGet(url); |
| | | com.alibaba.fastjson2.JSONObject json = com.alibaba.fastjson2.JSONObject.parseObject(res); |
| | | com.alibaba.fastjson2.JSONArray pool = null; |
| | | JSONObject json = JSONObject.parseObject(res); |
| | | JSONArray pool = null; |
| | | if (json.getJSONObject("data") != null) { |
| | | pool = json.getJSONObject("data").getJSONArray("pool"); |
| | | if (pool != null) { |
| | | for (int i = 0; i < pool.size(); i++) { |
| | | com.alibaba.fastjson2.JSONObject jsonObject = pool.getJSONObject(i); |
| | | JSONObject jsonObject = pool.getJSONObject(i); |
| | | String c = jsonObject.getString("c"); |
| | | if (c.equals(code)) { |
| | | pool.removeAll(pool); |
| | |
| | | //新闻列表 |
| | | List<SiteNews> newsList = this.siteNewsMapper.getTopNewsList(pageSize); |
| | | |
| | | String usCodeList = PropertiesUtil.getProperty("us_home_indices_code"); |
| | | String mxCodeList = PropertiesUtil.getProperty("mx_home_indices_code"); |
| | | List<String> usStockCodeList = Arrays.asList(usCodeList.split(",")); |
| | | List<String> mxStockCodeList = Arrays.asList(mxCodeList.split(",")); |
| | | /*String usCodeList = PropertiesUtil.getProperty("us_home_indices_code"); |
| | | String hkCodeList = PropertiesUtil.getProperty("hk_home_indices_code"); |
| | | String inCodeList = PropertiesUtil.getProperty("in_home_indices_code"); |
| | | String twCodeList = PropertiesUtil.getProperty("tw_home_indices_code");*/ |
| | | |
| | | List<StockConfig> stockConfigList = stockConfigMapper.selectList |
| | | (new LambdaQueryWrapper<StockConfig>() |
| | | .like(StockConfig::getCKey, EConfigKey.INDICES.getCode())); |
| | | |
| | | List<DataStockBean> usDataStockBeans = Lists.newArrayList(); |
| | | List<DataStockBean> mxDataStockBeans = Lists.newArrayList(); |
| | | for (int i = 0; i < usStockCodeList.size(); i++) { |
| | | String stockCode = usStockCodeList.get(i); |
| | | String stockType = EStockType.US.getCode(); |
| | | DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, stockCode); |
| | | // 获取K线数据 |
| | | Object kData = RedisKeyUtil.getCaCheStockKData(stockType, stockCode); |
| | | if (kData == null) { |
| | | //重新获取并缓存redis |
| | | kData = getKData(stockCode, "D", stockType); |
| | | RedisKeyUtil.setCaCheStockKData(stockType, stockCode, kData); |
| | | } |
| | | Gson gson = new Gson(); |
| | | List<kData> dataList = gson.fromJson(kData.toString(), new TypeToken<List<kData>>(){}.getType()); |
| | | cacheBaseStock.setKData(dataList); |
| | | cacheBaseStock.setStockType(stockType); |
| | | usDataStockBeans.add(cacheBaseStock); |
| | | } |
| | | for (int i = 0; i < mxStockCodeList.size(); i++) { |
| | | String stockCode = mxStockCodeList.get(i); |
| | | String stockType = EStockType.MX.getCode(); |
| | | DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, stockCode); |
| | | // 获取K线数据 |
| | | Object kData = RedisKeyUtil.getCaCheStockKData(stockType, stockCode); |
| | | if (kData == null) { |
| | | //重新获取并缓存redis |
| | | kData = getKData(stockCode, "D", stockType); |
| | | RedisKeyUtil.setCaCheStockKData(stockType, stockCode, kData); |
| | | } |
| | | Gson gson = new Gson(); |
| | | List<kData> dataList = gson.fromJson(kData.toString(), new TypeToken<List<kData>>(){}.getType()); |
| | | cacheBaseStock.setKData(dataList); |
| | | cacheBaseStock.setStockType(stockType); |
| | | mxDataStockBeans.add(cacheBaseStock); |
| | | } |
| | | List<DataStockBean> jpDataStockBeans = Lists.newArrayList(); |
| | | // 创建Gson对象(全局复用,避免重复创建) |
| | | Gson gson = new Gson(); |
| | | |
| | | // 统一处理各地区股票数据 |
| | | processStockData(stockConfigList, EStockType.US.getCode(), usDataStockBeans, gson); |
| | | processStockData(stockConfigList, EStockType.JP.getCode(), jpDataStockBeans, gson); |
| | | |
| | | // 组装返回结果 |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | resultMap.put("newsList", newsList); //新闻列表 |
| | | resultMap.put("usDataStockBeans", usDataStockBeans);//美国指数 |
| | | resultMap.put("mxDataStockBeans", mxDataStockBeans);//墨西哥指数 |
| | | resultMap.put("jpDataStockBeans", jpDataStockBeans);//日本指数 |
| | | return ServerResponse.createBySuccess(resultMap); |
| | | } catch (Exception e){ |
| | | e.printStackTrace(); |
| | |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | // 提取的通用处理方法 |
| | | private void processStockData(List<StockConfig> stockConfigList, String stockType, |
| | | List<DataStockBean> targetList, Gson gson) throws Exception { |
| | | String key = EConfigKey.getEConfigKeyByStockType(stockType).getCode(); |
| | | StockConfig stockConfig = stockConfigList.stream() |
| | | .filter(x -> x.getCKey().equals(key)).findFirst().orElse(null); |
| | | if (stockConfig == null) { |
| | | return; |
| | | } |
| | | String stockCodes = stockConfig.getCValue(); |
| | | String[] stockCodeList = stockCodes.split(","); |
| | | //实时获取数据 |
| | | //String result = RedisKeyUtil.doPost(stockCodes, stockType); |
| | | EStockType eStockType = EStockType.getEStockTypeByCode(stockType); |
| | | String result = HttpRequest.doGrabGet(eStockType.stockUrl + "indices?key=" + eStockType.getStockKey() + "&country_id=" + eStockType.getContryId()); |
| | | // 把JSON数据解析为List<DataStockBean> |
| | | Type listType = new TypeToken<List<DataStockBean>>(){}.getType(); |
| | | List<DataStockBean> list = new Gson().fromJson(result, listType); |
| | | |
| | | for (String stockCode : stockCodeList) { // 增强for循环简化代码 |
| | | // 获取基础股票数据 |
| | | //DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, stockCode); |
| | | DataStockBean cacheBaseStock = list.stream() |
| | | .filter(x -> stockCode.equals(x.getId())) |
| | | .findFirst().orElse(null); |
| | | if (cacheBaseStock == null) { // 增加空指针防护(可选,根据实际业务) |
| | | continue; |
| | | } |
| | | |
| | | // 获取K线数据(缓存优先) |
| | | Object kData = RedisKeyUtil.getCaCheStockKData(stockType, stockCode); |
| | | if (kData == null) { |
| | | // 缓存未命中时重新获取并缓存 |
| | | kData = getKData(stockCode, "D", stockType); |
| | | RedisKeyUtil.setCaCheStockKData(stockType, stockCode, kData); |
| | | } |
| | | |
| | | // 解析K线数据并设置到对象 |
| | | List<kData> dataList = gson.fromJson(kData.toString(), new TypeToken<List<kData>>(){}.getType()); |
| | | cacheBaseStock.setKData(dataList); |
| | | cacheBaseStock.setStockType(stockType); |
| | | |
| | | // 添加到目标集合 |
| | | targetList.add(cacheBaseStock); |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse getIndicesList(String stockType) { |
| | | try { |
| | | String codeList; |
| | | if(stockType.equals(EStockType.MX.getCode()) || stockType.equals("MX")) { |
| | | codeList = PropertiesUtil.getProperty("mx_home_indices_code"); |
| | | } else { |
| | | /*String codeList; |
| | | if(stockType.equals(EStockType.US.getCode())) { |
| | | codeList = PropertiesUtil.getProperty("us_home_indices_code"); |
| | | } else if(stockType.equals(EStockType.HK.getCode())) { |
| | | codeList = PropertiesUtil.getProperty("hk_home_indices_code"); |
| | | } else if(stockType.equals(EStockType.IN.getCode())) { |
| | | codeList = PropertiesUtil.getProperty("in_home_indices_code"); |
| | | } else if(stockType.equals(EStockType.TW.getCode())) { |
| | | codeList = PropertiesUtil.getProperty("tw_home_indices_code"); |
| | | } else |
| | | codeList = PropertiesUtil.getProperty("us_home_indices_code");*/ |
| | | |
| | | String key = EConfigKey.getEConfigKeyByStockType(stockType).getCode(); |
| | | StockConfig stockConfig = stockConfigMapper.selectOne(new LambdaQueryWrapper<StockConfig>() |
| | | .eq(StockConfig::getCKey, key)); |
| | | if (stockConfig == null) { |
| | | return ServerResponse.createByErrorMsg("stockConfig [" + key + "] is null"); |
| | | } |
| | | List<String> stockCodeList = Arrays.asList(codeList.split(",")); |
| | | List<String> stockCodeList = Arrays.asList(stockConfig.getCValue().split(",")); |
| | | |
| | | Map<Integer, Object> resultMap = new HashMap<>(); |
| | | for (int i = 0; i < stockCodeList.size(); i++) { |
| | |
| | | } |
| | | stockType = stock.getStockType(); |
| | | Map<String, Object> resultMap = new HashMap<>(); |
| | | DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, pid); |
| | | |
| | | //实时获取数据 |
| | | String s = RedisKeyUtil.doPost(pid, stockType); |
| | | Map<String, Object> stringObjectMap = RedisKeyUtil.jsonToMap(s); |
| | | resultMap.put("id", pid); |
| | | resultMap.put("stockType", stockType); |
| | | resultMap.put("name", stock.getStockName()); |
| | | resultMap.put("last", stringObjectMap.get("Last").toString()); |
| | | resultMap.put("chg", stringObjectMap.get("Chg").toString()); |
| | | resultMap.put("chgPct", stringObjectMap.get("ChgPct").toString()); |
| | | // 获取K线数据 |
| | | Object kData = getKData(pid, "D", stockType); |
| | | Gson gson = new Gson(); |
| | | List<kData> dataList = gson.fromJson(kData.toString(), new TypeToken<List<kData>>(){}.getType()); |
| | | resultMap.put("kData", dataList); |
| | | return ServerResponse.createBySuccess(resultMap); |
| | | |
| | | /*DataStockBean cacheBaseStock = RedisKeyUtil.getCacheBaseStock(stockType, pid); |
| | | if (cacheBaseStock != null) { |
| | | resultMap.put("id", cacheBaseStock.getId()); |
| | | resultMap.put("stockType", stockType); |
| | |
| | | List<kData> dataList = gson.fromJson(kData.toString(), new TypeToken<List<kData>>(){}.getType()); |
| | | resultMap.put("kData", dataList); |
| | | return ServerResponse.createBySuccess(resultMap); |
| | | } |
| | | }*/ |
| | | } catch (Exception e){ |
| | | e.printStackTrace(); |
| | | } |
| | |
| | | */ |
| | | @Override |
| | | public ServerResponse getStocksByKeyWords(int pageNum, int pageSize, String keyWords) { |
| | | |
| | | try { |
| | | PageHelper.startPage(pageNum, pageSize); |
| | | List<StockVOQuery> stocks = stockMapper.findStocksQuery(keyWords); |
| | | // 获取分页信息 |
| | | PageInfo<StockVOQuery> pageInfo = new PageInfo<>(stocks); |
| | | |
| | | /*if (!pageInfo.getList().isEmpty()) { |
| | | |
| | | }*/ |
| | | if (!pageInfo.getList().isEmpty()) { |
| | | pageInfo.getList().forEach(stock -> { |
| | | stock.setNowPrice(iPriceServices.getNowPrice(stock.getStockCode())); |
| | | }); |
| | | } |
| | | return ServerResponse.createBySuccess(pageInfo); |
| | | } catch (Exception e) { |
| | | log.error("StockAiService getStocksByKeyWords error", e); |
| | | } |
| | | return ServerResponse.createByError(); |
| | | } |
| | | |
| | | @Override |
| | | public ServerResponse getPremarketStock() { |
| | | try { |
| | | List<StockSetting> stockSettings = stockSettingMapper.selectList(new QueryWrapper<>()); |
| | | List<PremarketStockVO> resultList = new ArrayList<>(); |
| | | |
| | | Date now = new Date(); |
| | | |
| | | for (StockSetting setting : stockSettings) { |
| | | String startTime = setting.getStartTime(); |
| | | String endTime = setting.getEndTime(); |
| | | |
| | | // 判断当前时间是否在交易时间内(startTime和endTime是完整的日期时间格式) |
| | | if (isTimeInRange(now, startTime, endTime)) { |
| | | Stock stock = stockMapper.selectOne(new QueryWrapper<Stock>().eq("stock_code", setting.getStockCode())); |
| | | if (stock == null) { |
| | | continue; // 股票不存在,跳过 |
| | | } |
| | | |
| | | // 先获取真实数据,用于获取前收盘价和当前价格 |
| | | StockRealTimeBean realTimeStock = RedisKeyUtil.getCacheRealTimeStock(stock); |
| | | if (realTimeStock == null || realTimeStock.getPc() == null) { |
| | | continue; // 无法获取真实数据,跳过 |
| | | } |
| | | |
| | | // 获取前收盘价和当前价格(last) |
| | | BigDecimal prevClose = new BigDecimal(realTimeStock.getPc()); |
| | | BigDecimal last = new BigDecimal(realTimeStock.getLast()); |
| | | |
| | | // 计算盘前价格(根据StockSetting配置) |
| | | BigDecimal premarketPrice; |
| | | if ("0".equals(setting.getType())) { |
| | | // type=0: 直接指定价格 |
| | | premarketPrice = new BigDecimal(setting.getPrice()); |
| | | } else { |
| | | // type=1: 百分比调价格,基于last计算 |
| | | premarketPrice = last.multiply(new BigDecimal(setting.getPrice())); |
| | | } |
| | | |
| | | // 根据盘前价格计算涨跌幅 = (盘前价格 - 前收盘价) / 前收盘价 |
| | | BigDecimal hcrate = BigDecimal.ZERO; |
| | | if (prevClose.compareTo(BigDecimal.ZERO) > 0) { |
| | | hcrate = premarketPrice.subtract(prevClose) |
| | | .divide(prevClose, 4, RoundingMode.HALF_UP); |
| | | } |
| | | |
| | | // 格式化涨跌幅为带百分号的字符串 |
| | | String hcrateP = hcrate.multiply(new BigDecimal("100")) |
| | | .setScale(2, RoundingMode.HALF_UP) + "%"; |
| | | |
| | | PremarketStockVO vo = new PremarketStockVO(); |
| | | vo.setCode(setting.getStockCode()); |
| | | vo.setPrice(premarketPrice); // price返回盘前价格 |
| | | vo.setHcrate(hcrate); |
| | | vo.setHcrateP(hcrateP); |
| | | resultList.add(vo); |
| | | } |
| | | } |
| | | |
| | | return ServerResponse.createBySuccess(resultList); |
| | | } catch (Exception e) { |
| | | log.error("getPremarketStock error", e); |
| | | return ServerResponse.createByErrorMsg("查询盘前交易数据失败"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 判断当前时间是否在指定时间范围内 |
| | | * @param now 当前时间 |
| | | * @param startTime 开始时间,完整的日期时间格式 |
| | | * @param endTime 结束时间,完整的日期时间格式 |
| | | * @return |
| | | */ |
| | | private boolean isTimeInRange(Date now, String startTime, String endTime) { |
| | | try { |
| | | DateTime start = DateUtil.parseDateTime(startTime); |
| | | DateTime end = DateUtil.parseDateTime(endTime); |
| | | |
| | | // 判断当前时间是否在开始时间和结束时间之间 |
| | | return now.after(start) && now.before(end); |
| | | } catch (Exception e) { |
| | | log.error("isTimeInRange error", e); |
| | | return false; |
| | | } |
| | | } |
| | | } |