update top gainer and loser
This commit is contained in:
@@ -310,7 +310,7 @@ public class InvestingTask {
|
||||
}
|
||||
|
||||
@Scheduled(cron = "0 0 0/3 * * ?")
|
||||
@PostConstruct
|
||||
// @PostConstruct
|
||||
public void getBoerseNews(){
|
||||
String url_request = "https://www.boerse-online.de";
|
||||
|
||||
|
||||
@@ -538,7 +538,7 @@ public class MoneyApiController {
|
||||
|
||||
@ApiOperation(value = "股票推荐TopGainer", httpMethod = "GET")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE"),
|
||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE或者germany"),
|
||||
})
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 200, message = "" +
|
||||
@@ -548,42 +548,41 @@ public class MoneyApiController {
|
||||
@ResponseBody
|
||||
@EncryptFilter(decryptRequest = false)
|
||||
|
||||
public List<MoneyStockSuggestDTO> getTopGainer(@RequestParam String stockType) {
|
||||
public List<MoneyStockSuggestDTO> getTopGainer(@RequestParam(required = false, defaultValue = "germany") String stockType) {
|
||||
List<MoneyStockSuggestDTO> moneyStockSuggestDTOS = null;
|
||||
// 尝试从缓存中获取结果
|
||||
moneyStockSuggestDTOS = gainerStockSuggestCache.getIfPresent(stockType);
|
||||
// Use TradingView API for German stocks
|
||||
List<StockQuoteData> stockQuoteDataList = moneyApiService.getTopGainersFromTradingView();
|
||||
moneyStockSuggestDTOS = convertStockQuoteDataToMoneyStockSuggestDTO(stockQuoteDataList);
|
||||
|
||||
|
||||
if (moneyStockSuggestDTOS == null) {
|
||||
// 缓存未命中,执行业务查询
|
||||
if (StringUtils.equals(stockType, "nse")) {
|
||||
moneyStockSuggestDTOS = nseGainer();
|
||||
} else if (StringUtils.equals(stockType, "bse")) {
|
||||
moneyStockSuggestDTOS = bseGainer();
|
||||
}
|
||||
Map<Object, Boolean> map = new HashMap<>();
|
||||
moneyStockSuggestDTOS = moneyStockSuggestDTOS.stream()
|
||||
.filter(f -> StringUtils.isNotBlank(f.getStockName()))
|
||||
.filter(i -> map.putIfAbsent(i.getStockName(), Boolean.TRUE) == null).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(moneyStockSuggestDTOS)) {
|
||||
List<String> selfUlrList = moneyStockSuggestDTOS.stream().map(MoneyStockSuggestDTO::getStockName).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(selfUlrList)) {
|
||||
List<MoneyStock> all = moneyStockRepository.findAll(QMoneyStockPO.moneyStockPO.stockName.in(selfUlrList));
|
||||
if (CollectionUtils.isNotEmpty(all)) {
|
||||
moneyStockSuggestDTOS.stream().filter(f -> all.stream().anyMatch(s -> s.getStockName().equals(f.getStockName())))
|
||||
.forEach(f -> f.setScId(all.stream().filter(s -> s.getStockName().equals(f.getStockName())).findFirst().orElse(null).getMoneyScId()));
|
||||
}
|
||||
}
|
||||
gainerStockSuggestCache.put(stockType, moneyStockSuggestDTOS);
|
||||
}
|
||||
// 将结果放入缓存
|
||||
}
|
||||
return moneyStockSuggestDTOS;
|
||||
}
|
||||
|
||||
private List<MoneyStockSuggestDTO> convertStockQuoteDataToMoneyStockSuggestDTO(List<StockQuoteData> stockQuoteDataList) {
|
||||
List<MoneyStockSuggestDTO> result = new ArrayList<>();
|
||||
if (CollectionUtils.isNotEmpty(stockQuoteDataList)) {
|
||||
for (StockQuoteData stockQuoteData : stockQuoteDataList) {
|
||||
MoneyStockSuggestDTO dto = new MoneyStockSuggestDTO();
|
||||
dto.setStockName(stockQuoteData.getName());
|
||||
dto.setStockType("XETRA");
|
||||
dto.setLastPrice(String.valueOf(stockQuoteData.getClose()));
|
||||
dto.setChange(String.valueOf(stockQuoteData.getChange()));
|
||||
dto.setChangePercent(String.valueOf(stockQuoteData.getPercent_change()));
|
||||
dto.setHighPrice(String.valueOf(stockQuoteData.getHigh()));
|
||||
dto.setLowPrice(String.valueOf(stockQuoteData.getLow()));
|
||||
dto.setPrevClosePrice(String.valueOf(stockQuoteData.getPrevious_close()));
|
||||
dto.setScId(String.valueOf(stockQuoteData.getSymbol()));
|
||||
dto.setDispId(String.valueOf(stockQuoteData.getSymbol()));
|
||||
result.add(dto);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ApiOperation(value = "股票推荐TopLoser", httpMethod = "GET")
|
||||
@ApiImplicitParams({
|
||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE"),
|
||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE或者germany"),
|
||||
})
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(code = 200, message = "" +
|
||||
@@ -595,39 +594,9 @@ public class MoneyApiController {
|
||||
|
||||
public List<MoneyStockSuggestDTO> getTopLoser(@RequestParam String stockType) {
|
||||
List<MoneyStockSuggestDTO> moneyStockSuggestDTOS = null;
|
||||
moneyStockSuggestDTOS = loserStockSuggestCache.getIfPresent(stockType);
|
||||
if (null == moneyStockSuggestDTOS) {
|
||||
if (StringUtils.equals(stockType, "nse")) {
|
||||
moneyStockSuggestDTOS = nseTopLoser();
|
||||
} else if (StringUtils.equals(stockType, "bse")) {
|
||||
moneyStockSuggestDTOS = bseTopLoser();
|
||||
}
|
||||
Map<Object, Boolean> map = new HashMap<>();
|
||||
moneyStockSuggestDTOS = moneyStockSuggestDTOS.stream()
|
||||
.filter(f -> StringUtils.isNotBlank(f.getStockName()))
|
||||
.filter(i -> map.putIfAbsent(i.getStockName(), Boolean.TRUE) == null).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(moneyStockSuggestDTOS)) {
|
||||
moneyStockSuggestDTOS.stream().forEach(f -> f.setDispId(extractLastSegment(f.getStockUrl())));
|
||||
List<String> selfUlrList = moneyStockSuggestDTOS.stream().map(MoneyStockSuggestDTO::getStockName).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(selfUlrList)) {
|
||||
List<MoneyStock> all = moneyStockRepository.findAll(QMoneyStockPO.moneyStockPO.stockName.in(selfUlrList));
|
||||
if (CollectionUtils.isNotEmpty(all)) {
|
||||
moneyStockSuggestDTOS.stream().filter(f -> all.stream().anyMatch(s -> s.getStockName().equals(f.getStockName())))
|
||||
.forEach(f -> f.setScId(all.stream().filter(s -> s.getStockName().equals(f.getStockName())).findFirst().orElse(null).getMoneyScId()));
|
||||
}
|
||||
List<MoneyStockSuggestDTO> noScIdList = moneyStockSuggestDTOS.stream().filter(f -> StringUtils.isBlank(f.getScId())).collect(Collectors.toList());
|
||||
if (CollectionUtils.isNotEmpty(noScIdList)) {
|
||||
List<String> dispIdList = noScIdList.stream().map(MoneyStockSuggestDTO::getDispId).collect(Collectors.toList());
|
||||
List<MoneyStock> all1 = moneyStockRepository.findAll(QMoneyStockPO.moneyStockPO.selfDispId.in(dispIdList));
|
||||
if (CollectionUtils.isNotEmpty(all1)) {
|
||||
moneyStockSuggestDTOS.stream().filter(f -> all1.stream().anyMatch(s -> s.getSelfDispId().equals(f.getDispId())))
|
||||
.forEach(f -> f.setScId(all.stream().filter(s -> s.getSelfDispId().equals(f.getDispId())).findFirst().orElse(null).getMoneyScId()));
|
||||
}
|
||||
}
|
||||
}
|
||||
loserStockSuggestCache.put(stockType, moneyStockSuggestDTOS);
|
||||
}
|
||||
}
|
||||
List<StockQuoteData> stockQuoteDataList = moneyApiService.getTopLosersFromTradingView();
|
||||
moneyStockSuggestDTOS = convertStockQuoteDataToMoneyStockSuggestDTO(stockQuoteDataList);
|
||||
|
||||
return moneyStockSuggestDTOS;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import cn.qutaojing.common.utils.SpringUtils;
|
||||
import cn.stock.market.domain.basic.entity.Stock;
|
||||
import cn.stock.market.domain.basic.repository.StockRepository;
|
||||
import cn.stock.market.dto.*;
|
||||
import cn.stock.market.infrastructure.db.po.QStockPO;
|
||||
import cn.stock.market.web.config.Config;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -154,4 +155,107 @@ public class MoneyApiService {
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public List<StockQuoteData> getTopGainersFromTradingView() {
|
||||
List<StockQuoteData> result = getTopStocksFromTradingView("desc");
|
||||
// Sort by percent_change in descending order for gainers
|
||||
return result.stream()
|
||||
.sorted((a, b) -> Double.compare(b.getPercent_change(), a.getPercent_change()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<StockQuoteData> getTopLosersFromTradingView() {
|
||||
List<StockQuoteData> result = getTopStocksFromTradingView("asc");
|
||||
// Sort by percent_change in ascending order for losers
|
||||
return result.stream()
|
||||
.sorted((a, b) -> Double.compare(a.getPercent_change(), b.getPercent_change()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<StockQuoteData> getTopStocksFromTradingView(String sortOrder) {
|
||||
String url = "https://scanner.tradingview.com/germany/scan";
|
||||
|
||||
// Prepare request body
|
||||
String requestBody = "{\n" +
|
||||
" \"columns\": [\n" +
|
||||
" \"name\",\n" +
|
||||
" \"description\",\n" +
|
||||
" \"logoid\",\n" +
|
||||
" \"update_mode\",\n" +
|
||||
" \"type\",\n" +
|
||||
" \"currency\",\n" +
|
||||
" \"change\",\n" +
|
||||
" \"volume\",\n" +
|
||||
" \"exchange\"\n" +
|
||||
" ],\n" +
|
||||
" \"filter\": [\n" +
|
||||
" {\n" +
|
||||
" \"left\": \"is_primary\",\n" +
|
||||
" \"operation\": \"equal\",\n" +
|
||||
" \"right\": true\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"options\": {\n" +
|
||||
" \"lang\": \"en\"\n" +
|
||||
" },\n" +
|
||||
" \"range\": [\n" +
|
||||
" 0,\n" +
|
||||
" 30\n" +
|
||||
" ],\n" +
|
||||
" \"sort\": {\n" +
|
||||
" \"sortBy\": \"change\",\n" +
|
||||
" \"sortOrder\": \"" + sortOrder + "\"\n" +
|
||||
" },\n" +
|
||||
" \"markets\": [\n" +
|
||||
" \"germany\"\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.add("accept", "application/json");
|
||||
headers.add("accept-language", "en-US,en;q=0.9,vi;q=0.8,ug;q=0.7,fr;q=0.6");
|
||||
headers.add("origin", "https://www.tradingview.com");
|
||||
headers.add("referer", "https://www.tradingview.com/");
|
||||
headers.add("user-agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36");
|
||||
headers.add("Content-Type", "application/json");
|
||||
|
||||
HttpEntity<String> entity = new HttpEntity<>(requestBody, headers);
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
|
||||
try {
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
ObjectMapper mapper = new ObjectMapper();
|
||||
TradingViewResponse tradingViewResponse = mapper.readValue(response.getBody(), TradingViewResponse.class);
|
||||
|
||||
if (tradingViewResponse != null && tradingViewResponse.getData() != null) {
|
||||
// Extract symbols from TradingView response
|
||||
List<String> symbols = tradingViewResponse.getData().stream()
|
||||
.filter(item -> item.getS() != null && item.getS().startsWith("XETR:"))
|
||||
.map(item -> item.getS().substring(5)) // Remove "XETR:" prefix
|
||||
.limit(30)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
if (!symbols.isEmpty()) {
|
||||
// Find stocks in database
|
||||
List<Stock> stocks = stockRepository.findAll(QStockPO.stockPO.stockCode.in(symbols));
|
||||
|
||||
if (!stocks.isEmpty()) {
|
||||
// Get real-time quotes for these stocks
|
||||
List<StockQuoteData> stockQuoteDatas = getStocksQuote(stocks);
|
||||
for (StockQuoteData stockQuoteData : stockQuoteDatas) {
|
||||
Stock name = stocks.stream().filter(e->e.getStockCode().equals(stockQuoteData.getSymbol())).findFirst().orElse(null);
|
||||
if (name != null) {
|
||||
stockQuoteData.setName(name.getStockName());
|
||||
}
|
||||
}
|
||||
return stockQuoteDatas;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user