update top gainer and loser
This commit is contained in:
@@ -310,7 +310,7 @@ public class InvestingTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Scheduled(cron = "0 0 0/3 * * ?")
|
@Scheduled(cron = "0 0 0/3 * * ?")
|
||||||
@PostConstruct
|
// @PostConstruct
|
||||||
public void getBoerseNews(){
|
public void getBoerseNews(){
|
||||||
String url_request = "https://www.boerse-online.de";
|
String url_request = "https://www.boerse-online.de";
|
||||||
|
|
||||||
|
|||||||
@@ -538,7 +538,7 @@ public class MoneyApiController {
|
|||||||
|
|
||||||
@ApiOperation(value = "股票推荐TopGainer", httpMethod = "GET")
|
@ApiOperation(value = "股票推荐TopGainer", httpMethod = "GET")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE"),
|
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE或者germany"),
|
||||||
})
|
})
|
||||||
@ApiResponses(value = {
|
@ApiResponses(value = {
|
||||||
@ApiResponse(code = 200, message = "" +
|
@ApiResponse(code = 200, message = "" +
|
||||||
@@ -548,42 +548,41 @@ public class MoneyApiController {
|
|||||||
@ResponseBody
|
@ResponseBody
|
||||||
@EncryptFilter(decryptRequest = false)
|
@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;
|
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;
|
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")
|
@ApiOperation(value = "股票推荐TopLoser", httpMethod = "GET")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE"),
|
@ApiImplicitParam(name = "stockType", value = "BSE或者NSE或者germany"),
|
||||||
})
|
})
|
||||||
@ApiResponses(value = {
|
@ApiResponses(value = {
|
||||||
@ApiResponse(code = 200, message = "" +
|
@ApiResponse(code = 200, message = "" +
|
||||||
@@ -595,39 +594,9 @@ public class MoneyApiController {
|
|||||||
|
|
||||||
public List<MoneyStockSuggestDTO> getTopLoser(@RequestParam String stockType) {
|
public List<MoneyStockSuggestDTO> getTopLoser(@RequestParam String stockType) {
|
||||||
List<MoneyStockSuggestDTO> moneyStockSuggestDTOS = null;
|
List<MoneyStockSuggestDTO> moneyStockSuggestDTOS = null;
|
||||||
moneyStockSuggestDTOS = loserStockSuggestCache.getIfPresent(stockType);
|
List<StockQuoteData> stockQuoteDataList = moneyApiService.getTopLosersFromTradingView();
|
||||||
if (null == moneyStockSuggestDTOS) {
|
moneyStockSuggestDTOS = convertStockQuoteDataToMoneyStockSuggestDTO(stockQuoteDataList);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return moneyStockSuggestDTOS;
|
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.entity.Stock;
|
||||||
import cn.stock.market.domain.basic.repository.StockRepository;
|
import cn.stock.market.domain.basic.repository.StockRepository;
|
||||||
import cn.stock.market.dto.*;
|
import cn.stock.market.dto.*;
|
||||||
|
import cn.stock.market.infrastructure.db.po.QStockPO;
|
||||||
import cn.stock.market.web.config.Config;
|
import cn.stock.market.web.config.Config;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -154,4 +155,107 @@ public class MoneyApiService {
|
|||||||
|
|
||||||
return response;
|
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