diff --git a/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java index b29a919..657c8d4 100644 --- a/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java +++ b/src/main/generated/cn/stock/market/infrastructure/db/po/QStockIpoPO.java @@ -38,6 +38,7 @@ public class QStockIpoPO extends EntityPathBase { public final StringPath stockCode = createString("stockCode"); public final StringPath stockName = createString("stockName"); + public final StringPath exchangeType = createString("exchangeType"); public final NumberPath stockPrice = createNumber("stockPrice", java.math.BigDecimal.class); diff --git a/src/main/java/cn/stock/market/infrastructure/db/po/MoneyStockPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/MoneyStockPO.java index 959bdbe..911e59d 100644 --- a/src/main/java/cn/stock/market/infrastructure/db/po/MoneyStockPO.java +++ b/src/main/java/cn/stock/market/infrastructure/db/po/MoneyStockPO.java @@ -83,4 +83,6 @@ public class MoneyStockPO { /** * 是否展示 0是 1否 */ Integer isShow; + + Boolean useFromBseindia = false; } diff --git a/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java b/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java index b228275..abedbed 100644 --- a/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java +++ b/src/main/java/cn/stock/market/infrastructure/db/po/StockIpoPO.java @@ -79,6 +79,8 @@ public class StockIpoPO { * 申请总额 */ String apply; + String exchangeType; + /** * 市盈率 */ BigDecimal peRatio; diff --git a/src/main/java/cn/stock/market/infrastructure/job/Scraper.java b/src/main/java/cn/stock/market/infrastructure/job/Scraper.java index 7a4d8cd..54e0948 100644 --- a/src/main/java/cn/stock/market/infrastructure/job/Scraper.java +++ b/src/main/java/cn/stock/market/infrastructure/job/Scraper.java @@ -1,14 +1,20 @@ package cn.stock.market.infrastructure.job; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.stock.market.domain.basic.entity.BtodayStock; +import cn.stock.market.domain.basic.entity.MoneyStock; import cn.stock.market.domain.basic.entity.StockIpo; import cn.stock.market.domain.basic.repository.BtodayStockRepository; +import cn.stock.market.domain.basic.repository.MoneyStockRepository; import cn.stock.market.domain.basic.repository.StockIpoRepository; import cn.stock.market.dto.StockIpoDTO; +import cn.stock.market.infrastructure.db.po.QMoneyStockPO; import cn.stock.market.infrastructure.db.po.QStockIpoPO; import cn.stock.market.infrastructure.db.po.StockIpoPO; import cn.stock.market.infrastructure.db.repo.BtodayStockRepo; +import com.alibaba.druid.sql.visitor.functions.Now; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -31,14 +37,11 @@ import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import javax.annotation.PostConstruct; import java.io.IOException; import java.math.BigDecimal; import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -54,6 +57,10 @@ public class Scraper { private StockIpoRepository stockIpoRepository; private final ExecutorService executorService = Executors.newFixedThreadPool(5); + @Autowired + private MoneyStockRepository moneyStockRepository; + + private boolean times = false; @Scheduled(cron = "0 0 1 */2 * ?") @@ -104,6 +111,7 @@ public class Scraper { @Scheduled(cron = "0 0 18 * * ?") +// @PostConstruct @RequestMapping("/testScraperGetMoneyControllerNewIPO") public void getMoneyControllerNewIPOSchedule() { log.info("定时任务执行获取新股ipo的方法开始执行"); @@ -163,7 +171,28 @@ public class Scraper { stockIpo.setCreateDate(new Date()); stockIpo.setUpdateDate(new Date()); stockIpo.setSourceType("3"); - listStockIpoList.add(stockIpo); + + if (stockIpo.getStockCode() == null || stockIpo.getStockName() == null){ + continue; + } + + List exchanges = getIpoExchange(stockIpo.getStockName(), stockIpo.getStockCode()); + + for (String exchange : exchanges) { + StockIpo ipo = new StockIpo(); + ipo.setStockCode(stockIpo.getStockCode()); + ipo.setStockName(stockIpo.getStockName()); + ipo.setStockPrice(stockIpo.getStockPrice()); + ipo.setSubscriptionDate(stockIpo.getSubscriptionDate()); + ipo.setListingDate(stockIpo.getListingDate()); + ipo.setTotalNumber(stockIpo.getTotalNumber()); + ipo.setApply(stockIpo.getApply()); + ipo.setCreateDate(stockIpo.getCreateDate()); + ipo.setUpdateDate(stockIpo.getUpdateDate()); + ipo.setExchangeType(exchange); + + listStockIpoList.add(ipo); + } } for (int i = 0; i < upcomingData.size(); i++) { @@ -186,11 +215,37 @@ public class Scraper { stockIpo.setCreateDate(new Date()); stockIpo.setUpdateDate(new Date()); stockIpo.setSourceType("3"); - listStockIpoList.add(stockIpo); + + if (stockIpo.getStockCode() == null || stockIpo.getStockName() == null){ + continue; + } + + List exchanges = getIpoExchange(stockIpo.getStockName(), stockIpo.getStockCode()); + + for (String exchange : exchanges) { + StockIpo ipo = new StockIpo(); + ipo.setStockCode(stockIpo.getStockCode()); + ipo.setStockName(stockIpo.getStockName()); + ipo.setStockPrice(stockIpo.getStockPrice()); + ipo.setSubscriptionDate(stockIpo.getSubscriptionDate()); + ipo.setListingDate(stockIpo.getListingDate()); + ipo.setTotalNumber(stockIpo.getTotalNumber()); + ipo.setApply(stockIpo.getApply()); + ipo.setCreateDate(stockIpo.getCreateDate()); + ipo.setUpdateDate(stockIpo.getUpdateDate()); + ipo.setExchangeType(exchange); + + listStockIpoList.add(ipo); + } } // stockIpoRepository.saveAll(listStockIpoList); + if (!listStockIpoList.isEmpty()) + { + listStockIpoList = listStockIpoList.stream().filter(a -> StringUtils.isNotBlank(a.getStockName())).collect(Collectors.toList()); + } + List scIdList = Lists.transform(listStockIpoList, StockIpo::getStockCode); if(CollectionUtil.isNotEmpty(scIdList)){ List existStockIpoList = stockIpoRepository.findAll(QStockIpoPO.stockIpoPO.stockCode.in(scIdList)); @@ -205,6 +260,7 @@ public class Scraper { //保存全部的新股 if(CollectionUtil.isNotEmpty(listStockIpoList)){ stockIpoRepository.saveAll(listStockIpoList); + log.info("定时任务执行获取新股ipo的方法开始结束,保存了数据:{}", JSON.toJSONString(listStockIpoList)); }else { log.info("定时任务执行获取新股ipo的方法开始结束,没有数据"); @@ -225,6 +281,36 @@ public class Scraper { } + @Scheduled(cron = "0 0 19 * * ?") + @PostConstruct + @RequestMapping("/addMoneyStock") + public void addMoneyStock() { + log.info("定时任务执行获取新股ipo的方法开始执行"); + + List stockIpoList; + + if(!times){ + stockIpoList = stockIpoRepository.findAll(QStockIpoPO.stockIpoPO.listingDate.isNotNull() + .and(QStockIpoPO.stockIpoPO.listingDate.loe(DateTime.now())) + .and(QStockIpoPO.stockIpoPO.exchangeType.isNotNull()) + .and(QStockIpoPO.stockIpoPO.exchangeType.isNotEmpty()) + ); // first time run + + times = true; + } + else { + stockIpoList = stockIpoRepository.findAll(QStockIpoPO.stockIpoPO.listingDate.isNotNull() + .and(QStockIpoPO.stockIpoPO.listingDate.loe(DateTime.now()) + .and(QStockIpoPO.stockIpoPO.listingDate.goe(DateUtil.offsetDay(DateTime.now(), -3)))) + .and(QStockIpoPO.stockIpoPO.exchangeType.isNotNull()) + .and(QStockIpoPO.stockIpoPO.exchangeType.isNotEmpty()) + ); // from second run + } + + List moneyStockList = convertToMoneyStock(stockIpoList); + moneyStockRepository.saveAll(moneyStockList); + } + private static Timestamp convertStringToTimestamp(String dateString) { // 实现将字符串转换为 Timestamp 的逻辑 @@ -236,12 +322,6 @@ public class Scraper { } } - - - - - - private void processSubMap(Map sefUrlList) { for (Map.Entry entry : sefUrlList.entrySet()) { String companyName = entry.getKey(); @@ -378,4 +458,134 @@ public class Scraper { log.info("Getting web detail URL: " + url + "..."); return Jsoup.connect(url).ignoreContentType(true).execute().body(); } + + public List getIpoExchange(String stockName, String stockCode) { + List exchanges = new ArrayList<>(); + String url = "https://www.moneycontrol.com/ipo/{stockName}-{stockCode}-ipodetail"; + url = url.replace("{stockName}", stockName.toLowerCase().replace(" ", "-")).replace("{stockCode}", stockCode.toLowerCase()); + + org.apache.http.client.HttpClient client = HttpClients.createDefault(); + HttpGet request = new HttpGet(url); + try { + org.apache.http.HttpResponse response = client.execute(request); + + if (response.getStatusLine().getStatusCode() == 200) { + String responseBody = EntityUtils.toString(response.getEntity()); + Document doc = Jsoup.parse(responseBody); + + Element scriptTag = doc.selectFirst("script#__NEXT_DATA__"); + + if (scriptTag != null) { + String jsonDataStr = scriptTag.html(); + + com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(jsonDataStr); + log.info("获取到新股的json信息:" + jsonObject.toJSONString()); + + com.alibaba.fastjson.JSONObject pageProps = jsonObject.getJSONObject("props").getJSONObject("pageProps"); + com.alibaba.fastjson.JSONObject overview = pageProps.getJSONObject("ipoDetails").getJSONObject("ipoDetails").getJSONObject("overview"); + + String exchangeStr = overview.getString("listing_on"); + + if (exchangeStr != null && !exchangeStr.isEmpty() && !exchangeStr.equals("null")) { + exchanges.addAll(new ArrayList<>(Arrays.asList(exchangeStr.split(",")))); + } + } + } + } + catch (Exception e) { + log.info(e.getMessage()); + } + + if (exchanges.isEmpty()) { + exchanges.add(""); + } + + return exchanges; + } + + public List convertToMoneyStock(List stockIpoList) { + // Lấy danh sách tất cả stockCode và exchangeType từ stockIpoList + Set stockCodes = stockIpoList.stream().map(StockIpo::getStockCode).collect(Collectors.toSet()); + Set exchangeTypes = stockIpoList.stream().map(StockIpo::getExchangeType).collect(Collectors.toSet()); + + // Lấy tất cả các MoneyStock tồn tại trong database với stockCode và exchangeType trong stockIpoList + List existingMoneyStocks = moneyStockRepository.findAll( + QMoneyStockPO.moneyStockPO.moneyScId.in(stockCodes) + .and(QMoneyStockPO.moneyStockPO.stockType.in(exchangeTypes)) + ); + + // Lưu các stockCode và exchangeType đã tồn tại + Set existingKeys = existingMoneyStocks.stream() + .map(ms -> ms.getMoneyScId() + ms.getStockType()) + .collect(Collectors.toSet()); + + // Chỉ giữ những StockIpo chưa tồn tại + return stockIpoList.stream() + .filter(stockIpo -> !existingKeys.contains(stockIpo.getStockCode() + stockIpo.getExchangeType())) + .map(this::convert) + .collect(Collectors.toList()); + } + +// public List convertToMoneyStock(List stockIpoList) { +// return stockIpoList.stream() +// .filter(stockIpo -> !moneyStockRepository.exists( +// QMoneyStockPO.moneyStockPO.stockType.eq(stockIpo.getExchangeType()) +// .and(QMoneyStockPO.moneyStockPO.moneyScId.eq(stockIpo.getStockCode())) +// )) // Chỉ giữ những StockIpo chưa tồn tại +// .map(this::convert) +// .collect(Collectors.toList()); +// } + + private MoneyStock convert(StockIpo stockIpo) { + MoneyStock moneyStock = new MoneyStock(); + + moneyStock.setStockName(stockIpo.getStockName()); + moneyStock.setMoneyScId(stockIpo.getStockCode()); + moneyStock.setSelfDispId(stockIpo.getStockCode()); + moneyStock.setStockType(stockIpo.getExchangeType()); + moneyStock.setSaveTime(DateTime.now()); + moneyStock.setNseIndiaId(getNSEId(stockIpo)); + + return moneyStock; + } + + private String getNSEId(StockIpo stockIpo){ + String url = "https://priceapi.moneycontrol.com/pricefeed/" + stockIpo.getExchangeType().toLowerCase() + "/equitycash/" + stockIpo.getStockCode(); + // 创建 HttpClient 实例 + HttpClient client = HttpClients.createDefault(); + // 创建 HttpGet 请求 + HttpGet request = new HttpGet(url); + try { + // 执行请求 + HttpResponse response = client.execute(request); + + // 检查请求是否成功 + if (response.getStatusLine().getStatusCode() == 200) { + // 获取响应体 + String responseBody = EntityUtils.toString(response.getEntity()); + + if (responseBody != null) { + // 获取 JSON 数据 + + // 将 JSON 字符串解析为 Java JSONObject + JSONObject jsonObject = JSONObject.parseObject(responseBody); + log.info("获取到新股的json信息:" + jsonObject.toJSONString()); + + JSONObject jsonData = jsonObject.getJSONObject("data"); + + if(stockIpo.getExchangeType().equals("NSE")){ + return jsonData.getString("NSEID"); + } + else if(stockIpo.getExchangeType().equals("BSE")){ + return jsonData.getString("BSEID"); + } + } + } + } + catch (Exception e){ + log.info(e.getMessage()); + } + + return ""; + } } diff --git a/src/main/java/cn/stock/market/web/MoneyApiController.java b/src/main/java/cn/stock/market/web/MoneyApiController.java index adfc339..e905a43 100644 --- a/src/main/java/cn/stock/market/web/MoneyApiController.java +++ b/src/main/java/cn/stock/market/web/MoneyApiController.java @@ -6,9 +6,7 @@ import cn.stock.market.domain.basic.entity.MoneyStock; import cn.stock.market.domain.basic.entity.OptionalStock; import cn.stock.market.domain.basic.repository.MoneyStockRepository; import cn.stock.market.domain.basic.repository.OptionalStockRepository; -import cn.stock.market.dto.OptionalStockResponse; -import cn.stock.market.dto.StockHistoryRequest; -import cn.stock.market.dto.StockHistoryResponse; +import cn.stock.market.dto.*; import cn.stock.market.dto.query.StockChartDto; import cn.stock.market.infrastructure.db.po.QMoneyStockPO; import cn.stock.market.utils.HttpRequest; @@ -21,6 +19,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.cache.Cache; import com.google.common.cache.CacheBuilder; import com.google.common.collect.Lists; +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; import io.swagger.annotations.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiImplicitParams; @@ -40,9 +41,7 @@ import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.jsoup.nodes.Element; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.http.HttpMethod; -import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseEntity; +import org.springframework.http.*; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; @@ -53,8 +52,11 @@ import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriUtils; import java.io.IOException; +import java.math.BigDecimal; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; +import java.text.ParseException; +import java.text.SimpleDateFormat; import java.time.Instant; import java.time.YearMonth; import java.time.ZoneId; @@ -194,7 +196,6 @@ public class MoneyApiController { @GetMapping({"/market/api/market/money/getStockDetail", "/api/market/money/getStockDetail"}) @ResponseBody @EncryptFilter(decryptRequest = false) - public ServerResponse getStockDetail(@RequestParam String stockType, @RequestParam String symbol) { MoneyStock moneyStock = moneyStockRepository.findOne(QMoneyStockPO.moneyStockPO.stockType.eq(stockType) .and(QMoneyStockPO.moneyStockPO.moneyScId.eq(symbol)) @@ -218,8 +219,56 @@ public class MoneyApiController { return ServerResponse.createBySuccess(json1); } - String url = String.format("https://priceapi.moneycontrol.com/pricefeed/%s/equitycash/%s", stockType, symbol); + String url = String.format("https://priceapi.moneycontrol.com/pricefeed/%s/equitycash/%s", stockType.toLowerCase(), symbol); int maxRetries = 3; + if (moneyStock.getUseFromBseindia()) { + String bseUrl = "https://api.bseindia.com/BseIndiaAPI/api/getScripHeaderData/w?Debtflag=&scripcode=" + moneyStock.getNseIndiaId() + "&seriesid="; + HttpHeaders headers = new HttpHeaders(); + headers.add("accept", "application/json, text/plain, */*"); + headers.add("accept-language", "en-US,en;q=0.9,vi;q=0.8"); + headers.add("origin", "https://www.bseindia.com"); + headers.add("referer", "https://www.bseindia.com/"); + headers.add("sec-ch-ua", "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""); + headers.add("sec-ch-ua-mobile", "?0"); + headers.add("sec-ch-ua-platform", "\"Windows\""); + headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"); + + HttpEntity entity = new HttpEntity<>(headers); + + try { + ResponseEntity responseEntity = restTemplate.exchange(bseUrl, HttpMethod.GET, entity, String.class); + if (responseEntity.getStatusCode().value() == 200 && responseEntity.getBody() != null) { + JSONObject bseData = JSONObject.parseObject(responseEntity.getBody()); + JSONObject json1 = new JSONObject(); + json1.put("company", bseData.getJSONObject("Cmpname").getString("FullN")); + json1.put("pricepercentchange", bseData.getJSONObject("CurrRate").getString("PcChg")); + json1.put("stockType", stockType); + json1.put("pricechange", bseData.getJSONObject("CurrRate").getString("Chg")); + json1.put("pricecurrent", bseData.getJSONObject("CurrRate").getString("LTP")); + json1.put("priceprevclose", bseData.getJSONObject("Header").getString("PrevClose")); + json1.put("PREVDATE", ""); + + json1.put("dataSourceType", "3"); + json1.put("symbol", symbol); + json1.put("BSEID", moneyStock.getNseIndiaId()); + json1.put("NSEID", moneyStock.getNseIndiaId()); + json1.put("LTH", bseData.getJSONObject("Header").getString("High")); + json1.put("LTL", bseData.getJSONObject("Header").getString("Low")); + json1.put("OPN", bseData.getJSONObject("Header").getString("Open")); + + + if (moneyStock != null) { + json1.put("id", moneyStock.getId()); + } + + json1.put("VOL", this.getVolume(moneyStock.getNseIndiaId())); + return ServerResponse.createBySuccess(json1); + } + } catch (Exception e) { + System.err.println("Error fetching data from BSE India: " + e.getMessage()); + } + } + for (int retry = 1; retry <= maxRetries; retry++) { try { ResponseEntity responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, String.class); @@ -280,6 +329,57 @@ public class MoneyApiController { return null; } + private String getVolume(String scripcode) { + String url = "https://api.bseindia.com/BseIndiaAPI/api/StockTrading/w?flag="etype=EQ&scripcode=" + scripcode; + RestTemplate restTemplate = new RestTemplate(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("accept", "application/json, text/plain, */*"); + headers.add("accept-language", "en-US,en;q=0.9,vi;q=0.8"); + headers.add("origin", "https://www.bseindia.com"); + headers.add("referer", "https://www.bseindia.com/"); + headers.add("sec-ch-ua", "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""); + headers.add("sec-ch-ua-mobile", "?0"); + headers.add("sec-ch-ua-platform", "\"Windows\""); + headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"); + + HttpEntity entity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); + BigDecimal volume = BigDecimal.ZERO; + + if (response.getStatusCode().value() == 200 && response.getBody() != null) { + JSONObject volumeData = JSONObject.parseObject(response.getBody()); + if (volumeData.getString("TTQ") != null) { + volume = new BigDecimal(volumeData.getString("TTQ")); + } + } + return volume.toString(); + } + + private String getChartData(String scripcode, String resolution) { + String url = "https://charting.bseindia.com/charting/RestDataProvider.svc/getDat?exch=B&type=b&mode=bseL&fromdate=01-01-1991-01%3A01%3A00-AM&scode=" + scripcode; + if (resolution.equals("H")) { + url = "https://charting.bseindia.com/charting/RestDataProvider.svc/getDatI?exch=B&type=b&mode=bseL&fromdate=01-01-1991-01%3A01%3A00-AM&scode=" + scripcode; + } + RestTemplate restTemplate = new RestTemplate(); + + HttpHeaders headers = new HttpHeaders(); + headers.add("accept", "application/json, text/plain, */*"); + headers.add("accept-language", "en-US,en;q=0.9,vi;q=0.8"); + headers.add("origin", "https://www.bseindia.com"); + headers.add("referer", "https://www.bseindia.com/"); + headers.add("sec-ch-ua", "\"Google Chrome\";v=\"131\", \"Chromium\";v=\"131\", \"Not_A Brand\";v=\"24\""); + headers.add("sec-ch-ua-mobile", "?0"); + headers.add("sec-ch-ua-platform", "\"Windows\""); + headers.add("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"); + + HttpEntity entity = new HttpEntity<>(headers); + + ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); + + return response.getBody(); + } private static List nseActives() { List list = new ArrayList<>(); @@ -696,6 +796,45 @@ public class MoneyApiController { return moneyStockSuggestDTOS; } + private static void addToListDouble(List list, String value) { + String[] values = value.split(","); + for (String v : values) { + list.add(Double.parseDouble(v)); + } + } + + private static void addToList(List list, String value) { + String[] values = value.split(","); + for (String v : values) { + list.add(Math.round(Double.parseDouble(v))); + } + } + + private static void addDatesToList(List list, String value) { + String[] dates = value.split(","); + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", Locale.US); + for (String dateStr : dates) { + try { + Date date = sdf.parse(dateStr); + list.add(date.getTime() / 1000); + } catch (ParseException e) { + e.printStackTrace(); + } + } + } + + private Long convertToTimestamp(String dateStr) { + try { + SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", Locale.US); + Date date = sdf.parse(dateStr); + return date.getTime() / 1000; + } catch (ParseException e) { + e.printStackTrace(); + return 0L; + } + } + + @GetMapping({"/market/api/market/money/history/kLine", "/api/market/money/history/kLine"}) @ApiOperation(value = "获取kline的money数据源", notes = "获取kline的money数据源", response = StockHistoryResponse.class) @@ -712,6 +851,166 @@ public class MoneyApiController { public ResponseEntity getStockHistory(@RequestParam String symbol, @RequestParam String resolution ) { + MoneyStock moneyStock1 = moneyStockRepository.findOne( + QMoneyStockPO.moneyStockPO.nseIndiaId.eq(symbol) + .and(QMoneyStockPO.moneyStockPO.isLock.eq(0)) + .and(QMoneyStockPO.moneyStockPO.isShow.eq(0))) + .orElse(null); + + if (moneyStock1 != null && moneyStock1.getUseFromBseindia()) { + + String json = this.getChartData(moneyStock1.getNseIndiaId(), resolution); + + Gson gson = new Gson(); + + JsonObject outerJson = gson.fromJson(json, JsonObject.class); + + String innerJsonString; + + if (resolution.equals("H")) { + innerJsonString = outerJson.get("getDatIResult").getAsString(); + } else { + innerJsonString = outerJson.get("getDatResult").getAsString(); + } + + JsonObject innerJson = gson.fromJson(innerJsonString, JsonObject.class); + + JsonArray dataInputValues = innerJson.getAsJsonArray("DataInputValues"); + + List openList = new ArrayList<>(); + List highList = new ArrayList<>(); + List lowList = new ArrayList<>(); + List closeList = new ArrayList<>(); + List volumeList = new ArrayList<>(); + List dateList = new ArrayList<>(); + + Map latestDataMap = new LinkedHashMap<>(); + + if (dataInputValues.size() > 0) { + JsonObject dataObject = dataInputValues.get(0).getAsJsonObject(); + + JsonArray openArray = dataObject.getAsJsonArray("OpenData"); + JsonArray highArray = dataObject.getAsJsonArray("HighData"); + JsonArray lowArray = dataObject.getAsJsonArray("LowData"); + JsonArray closeArray = dataObject.getAsJsonArray("CloseData"); + JsonArray volumeArray = dataObject.getAsJsonArray("VolumeData"); + JsonArray dateArray = dataObject.getAsJsonArray("DateData"); + + if (resolution.equals("H")) { + openArray.forEach(o -> addToListDouble(openList, o.getAsJsonObject().get("Open").getAsString())); + highArray.forEach(h -> addToListDouble(highList, h.getAsJsonObject().get("High").getAsString())); + lowArray.forEach(l -> addToListDouble(lowList, l.getAsJsonObject().get("Low").getAsString())); + closeArray.forEach(c -> addToListDouble(closeList, c.getAsJsonObject().get("Close").getAsString())); + volumeArray.forEach(v -> addToList(volumeList, v.getAsJsonObject().get("Volume").getAsString())); + dateArray.forEach(d -> addDatesToList(dateList, d.getAsJsonObject().get("Date").getAsString())); + } else { + for (int i = 0; i < openArray.size(); i++) { + String open = openArray.get(i).getAsJsonObject().get("Open").getAsString(); + String high = highArray.get(i).getAsJsonObject().get("High").getAsString(); + String low = lowArray.get(i).getAsJsonObject().get("Low").getAsString(); + String close = closeArray.get(i).getAsJsonObject().get("Close").getAsString(); + String volume = volumeArray.get(i).getAsJsonObject().get("Volume").getAsString(); + String dateStr = dateArray.get(i).getAsJsonObject().get("Date").getAsString(); + + Long timestamp = convertToTimestamp(dateStr); + + String dateTimeKey = dateStr; + + JsonObject dataJson = new JsonObject(); + dataJson.addProperty("Open", open); + dataJson.addProperty("High", high); + dataJson.addProperty("Low", low); + dataJson.addProperty("Close", close); + dataJson.addProperty("Volume", volume); + dataJson.addProperty("Date", dateStr); + + latestDataMap.put(dateTimeKey, dataJson); + } + + latestDataMap.forEach((key, value) -> { + // Lấy giá trị các trường Open, High, Low, Close, Volume, Date từ dữ liệu + String openData = value.get("Open").getAsString(); + String highData = value.get("High").getAsString(); + String lowData = value.get("Low").getAsString(); + String closeData = value.get("Close").getAsString(); + String volumeData = value.get("Volume").getAsString(); + String dateData = value.get("Date").getAsString(); + + // Tách các giá trị trong chuỗi bằng dấu phẩy + String[] openValues = openData.split(","); + String[] highValues = highData.split(","); + String[] lowValues = lowData.split(","); + String[] closeValues = closeData.split(","); + String[] volumeValues = volumeData.split(","); + String[] dateValues = dateData.split(","); + + for (int i = 0; i < openValues.length; i++) { + double open = Double.parseDouble(openValues[i]); + double high = Double.parseDouble(highValues[i]); + double low = Double.parseDouble(lowValues[i]); + double close = Double.parseDouble(closeValues[i]); + long volume = Math.round(Double.parseDouble(volumeValues[i])); + long timestamp = convertToTimestamp(dateValues[i]); + + int index = dateList.indexOf(timestamp); + if (index == -1) { + dateList.add(timestamp); + openList.add(open); + highList.add(high); + lowList.add(low); + closeList.add(close); + volumeList.add(volume); + } else { + openList.set(index, open); + highList.set(index, high); + lowList.set(index, low); + closeList.set(index, close); + volumeList.set(index, volume); + } + } + }); + } + + StockHistoryResponse response = new StockHistoryResponse(); + response.setS("ok"); + response.setT(dateList); + response.setO(openList); + response.setH(highList); + response.setL(lowList); + response.setC(closeList); + response.setV(volumeList); + +// if (resolution.equals("H")) { +// Set desiredTimes = new HashSet<>(Arrays.asList("09:30", "10:30", "11:30", "12:30", "13:30", "14:30")); +// +// // Filter data based on timestamps +// SimpleDateFormat sdf = new SimpleDateFormat("HH:mm"); +// List indicesToKeep = new ArrayList<>(); +// for (int i = 0; i < dateList.size(); i++) { +// String time = sdf.format(new Date(dateList.get(i) * 1000)); +// if (desiredTimes.contains(time)) { +// indicesToKeep.add(i); +// } +// } +// +// // Filter corresponding data +// List filteredT = indicesToKeep.stream().map(dateList::get).collect(Collectors.toList()); +// List filteredO = indicesToKeep.stream().map(openList::get).collect(Collectors.toList()); +// List filteredH = indicesToKeep.stream().map(highList::get).collect(Collectors.toList()); +// List filteredL = indicesToKeep.stream().map(lowList::get).collect(Collectors.toList()); +// List filteredC = indicesToKeep.stream().map(closeList::get).collect(Collectors.toList()); +// List filteredV = indicesToKeep.stream().map(volumeList::get).collect(Collectors.toList()); +// response.setT(filteredT); +// response.setO(filteredO); +// response.setH(filteredH); +// response.setL(filteredL); +// response.setC(filteredC); +// response.setV(filteredV); +// } + return ResponseEntity.ok(response); + } + } + // 向外部API发起请求,并获取响应 StockHistoryRequest request = new StockHistoryRequest(); request.setSymbol(symbol); diff --git a/src/main/resources/application-base-alpha.yml b/src/main/resources/application-base-alpha.yml index 6572790..590859e 100644 --- a/src/main/resources/application-base-alpha.yml +++ b/src/main/resources/application-base-alpha.yml @@ -3,9 +3,9 @@ spring: show-sql: true # Redis配置 redis: - host: lb-b6sze686-7db6hgvsx05ef8nz.clb.sg-tencentclb.net + host: 43.156.40.39 password: a5v8b86P4mVzFlUqJV - port: 56379 + port: 30031 database: 1 lettuce: pool: @@ -17,7 +17,7 @@ spring: datasource: stock-market: driver-class-name: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://lb-1ju43bvw-p0ecnv4by9ju8six.clb.ap-singapore.tencentclb.com:53306/india_stock?useUnicode=true&characterEncoding=utf-8 + url: jdbc:mysql://43.156.40.39:30030/india_stock?useUnicode=true&characterEncoding=utf-8 username: root password: uNejHIFQGJOUtYTmE maxActive: 500