From 549345719a70780e893a2de04b9800dfa92541c6 Mon Sep 17 00:00:00 2001 From: quangnguyen202 Date: Thu, 26 Sep 2024 16:51:41 +0700 Subject: [PATCH] Add alternate source --- .../infrastructure/db/po/MoneyStockPO.java | 4 + .../stock/market/utils/NseIndiaRequest.java | 133 ++++++++++-------- .../stock/market/web/MoneyApiController.java | 26 ++-- 3 files changed, 88 insertions(+), 75 deletions(-) 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 8e73f8e..959bdbe 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 @@ -60,6 +60,10 @@ public class MoneyStockPO { * NSE India的id */ String nseIndiaId; + /** + * NSE India Chart的id */ + String nseIndiaChartId; + /** * 自有self_url */ String selfUrl; diff --git a/src/main/java/cn/stock/market/utils/NseIndiaRequest.java b/src/main/java/cn/stock/market/utils/NseIndiaRequest.java index 3fa4bbe..9868600 100644 --- a/src/main/java/cn/stock/market/utils/NseIndiaRequest.java +++ b/src/main/java/cn/stock/market/utils/NseIndiaRequest.java @@ -2,18 +2,21 @@ package cn.stock.market.utils; import cn.stock.market.dto.StockHistoryRequest; import cn.stock.market.dto.StockHistoryResponse; -import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; +import com.fasterxml.jackson.databind.ObjectMapper; import okhttp3.*; +import org.apache.commons.lang.StringUtils; import java.io.IOException; -import java.text.SimpleDateFormat; -import java.time.Instant; import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class NseIndiaRequest { private static final String NSE_INDIA_URL = "https://www.nseindia.com"; + private static final String NSE_INDIA_CHART_URL = "https://charting.nseindia.com"; private static final OkHttpClient client; + private static final ObjectMapper objectMapper = new ObjectMapper(); static { client = new OkHttpClient.Builder() @@ -47,8 +50,8 @@ public class NseIndiaRequest { return request; } - private static void initCookie() { - Request request = createRequest(NSE_INDIA_URL); + private static void initCookie(String url) { + Request request = createRequest(url); try (Response response = client.newCall(request).execute()) { if (!response.isSuccessful()) { throw new IOException("Failed to fetch initial cookies"); @@ -58,8 +61,35 @@ public class NseIndiaRequest { } } + private static Integer getCode(String symbol) { + Request request = createRequest(NSE_INDIA_CHART_URL + "//Charts/GetEQMasters").newBuilder() + .addHeader("referer", NSE_INDIA_CHART_URL) + .addHeader("origin", NSE_INDIA_CHART_URL) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("Failed to get EQ code"); + } + + String result = response.body().string(); + + String regex = "(\\d+)\\|" + symbol + "\\|.*"; + Pattern pattern = Pattern.compile(regex); + Matcher matcher = pattern.matcher(result); + + if (matcher.find()) { + return Integer.valueOf(matcher.group(1)); + } + throw new IOException("No data found"); + + } catch (IOException e) { + throw new RuntimeException("Failed to get EQ code", e); + } + } + public static JSONObject stockByJYSFromHttp(String stockType, String symbol, String nseIndiaId) { - initCookie(); + initCookie(NSE_INDIA_URL); String url = NSE_INDIA_URL + "/api/quote-equity?symbol=" + nseIndiaId; Request request = createRequest(url).newBuilder() @@ -96,18 +126,44 @@ public class NseIndiaRequest { } } - public static StockHistoryResponse stockKLineFromHttp(StockHistoryRequest stockHistoryRequest) { - initCookie(); + public static StockHistoryResponse stockKLineFromHttp(StockHistoryRequest stockHistoryRequest, String resolution) { + initCookie(NSE_INDIA_CHART_URL); - SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy"); - String fromDate = sdf.format(new Date(stockHistoryRequest.getFrom() * 1000)); - String toDate = sdf.format(new Date(stockHistoryRequest.getTo() * 1000)); + Integer code = getCode(stockHistoryRequest.getSymbol()); - String url = String.format("%s/api/historical/cm/equity?symbol=%s&from=%s&to=%s", NSE_INDIA_URL, stockHistoryRequest.getSymbol(), fromDate, toDate); + int interval = 1; + if (StringUtils.equals("H", resolution)) { + resolution = "I"; + interval = 60; + } - Request request = createRequest(url).newBuilder() - .addHeader("referer", NSE_INDIA_URL) - .addHeader("origin", NSE_INDIA_URL) + Map body = new HashMap<>(); + body.put("chartPeriod", resolution); + body.put("chartStart", 0); + body.put("exch", "N"); + body.put("fromDate", 0); + body.put("instrType", "C"); + body.put("scripCode", code); + body.put("timeInterval", interval); + body.put("toDate", stockHistoryRequest.getTo() + 18000); + body.put("ulToken", code); + + String payload; + try { + payload = objectMapper.writeValueAsString(body); + } catch (Exception e) { + throw new RuntimeException("Failed to serialize body", e); + } + + RequestBody requestBody = RequestBody.create( + MediaType.get("application/json; charset=utf-8"), + payload + ); + + Request request = createRequest(NSE_INDIA_CHART_URL + "//Charts/symbolhistoricaldata/").newBuilder() + .addHeader("referer", NSE_INDIA_CHART_URL) + .addHeader("origin", NSE_INDIA_CHART_URL) + .post(requestBody) .build(); try (Response response = client.newCall(request).execute()) { @@ -115,52 +171,7 @@ public class NseIndiaRequest { throw new IOException("Request failed with code: " + response.code()); } - JSONObject jsonData = JSONObject.parseObject(response.body().string()); - JSONArray data =jsonData.getJSONArray("data"); - - StockHistoryResponse result = new StockHistoryResponse(); - List tList = new ArrayList<>(); - List oList = new ArrayList<>(); - List hList = new ArrayList<>(); - List lList = new ArrayList<>(); - List cList = new ArrayList<>(); - List vList = new ArrayList<>(); - - for (int i = 0; i < data.size(); i++) { - Long t, v; - Double o, h, l, c; - - try { - JSONObject jsonObject = data.getJSONObject(i); - - String timestampStr = jsonObject.getString("TIMESTAMP"); - Instant instant = Instant.parse(timestampStr); - t = instant.toEpochMilli() / 1000; - - o = jsonObject.getDouble("CH_OPENING_PRICE"); - c = jsonObject.getDouble("CH_CLOSING_PRICE"); - h = jsonObject.getDouble("CH_TRADE_HIGH_PRICE"); - l = jsonObject.getDouble("CH_TRADE_LOW_PRICE"); - v = jsonObject.getLong("CH_TOT_TRADED_VAL"); - - } catch (Exception e) { - continue; - } - - tList.add(t); - oList.add(o); - hList.add(h); - lList.add(l); - cList.add(c); - vList.add(v); - } - - result.setT(tList); - result.setO(oList); - result.setH(hList); - result.setL(lList); - result.setC(cList); - result.setV(vList); + StockHistoryResponse result = objectMapper.readValue(response.body().string(), StockHistoryResponse.class); return result; } catch (IOException e) { diff --git a/src/main/java/cn/stock/market/web/MoneyApiController.java b/src/main/java/cn/stock/market/web/MoneyApiController.java index d70667b..27547a7 100644 --- a/src/main/java/cn/stock/market/web/MoneyApiController.java +++ b/src/main/java/cn/stock/market/web/MoneyApiController.java @@ -745,22 +745,20 @@ public class MoneyApiController { // API request successful, return the response return ResponseEntity.ok(response); } else { - if (!StringUtils.equals("H", resolution)) { - try { - MoneyStock moneyStock = moneyStockRepository.findOne((QMoneyStockPO.moneyStockPO.moneyScId.eq(symbol)) - .and(QMoneyStockPO.moneyStockPO.isLock.eq(0)) - .and(QMoneyStockPO.moneyStockPO.isShow.eq(0))) - .orElse(null); + try { + MoneyStock moneyStock = moneyStockRepository.findOne((QMoneyStockPO.moneyStockPO.moneyScId.eq(symbol)) + .and(QMoneyStockPO.moneyStockPO.isLock.eq(0)) + .and(QMoneyStockPO.moneyStockPO.isShow.eq(0))) + .orElse(null); - if (moneyStock != null && moneyStock.getNseIndiaId() != null && !moneyStock.getNseIndiaId().isEmpty()) { - request.setSymbol(moneyStock.getNseIndiaId()); - response = NseIndiaRequest.stockKLineFromHttp(request); - return ResponseEntity.ok(response); - } - } catch (Exception e) { - log.error("Failed to get data from nseindia.", e.getMessage()); - return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); + if (moneyStock != null && moneyStock.getNseIndiaChartId() != null && !moneyStock.getNseIndiaChartId().isEmpty()) { + request.setSymbol(moneyStock.getNseIndiaChartId()); + response = NseIndiaRequest.stockKLineFromHttp(request, resolution); + return ResponseEntity.ok(response); } + } catch (Exception e) { + log.error("Failed to get data from nseindia.", e.getMessage()); + return ResponseEntity.status(HttpStatus.BAD_REQUEST).build(); } // All retries failed, return an error response