Compare commits
8 Commits
feature/kl
...
bug/crawl_
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5b16f1f2c9 | ||
|
|
b8d4e0d3f2 | ||
|
|
c19277e390 | ||
|
|
514875878f | ||
|
|
4257541342 | ||
|
|
441adac15a | ||
|
|
ba29ab98c7 | ||
|
|
94ec73874b |
6
pom.xml
6
pom.xml
@@ -185,6 +185,12 @@
|
|||||||
<version>30.1-jre</version>
|
<version>30.1-jre</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.httpcomponents</groupId>
|
||||||
|
<artifactId>httpclient</artifactId>
|
||||||
|
<version>4.5.13</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package cn.stock.market.infrastructure.db.po;
|
||||||
|
|
||||||
|
import static com.querydsl.core.types.PathMetadataFactory.*;
|
||||||
|
|
||||||
|
import com.querydsl.core.types.dsl.*;
|
||||||
|
|
||||||
|
import com.querydsl.core.types.PathMetadata;
|
||||||
|
import javax.annotation.Generated;
|
||||||
|
import com.querydsl.core.types.Path;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QOptionalStockPO is a Querydsl query type for OptionalStockPO
|
||||||
|
*/
|
||||||
|
@Generated("com.querydsl.codegen.EntitySerializer")
|
||||||
|
public class QOptionalStockPO extends EntityPathBase<OptionalStockPO> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1161631810L;
|
||||||
|
|
||||||
|
public static final QOptionalStockPO optionalStockPO = new QOptionalStockPO("optionalStockPO");
|
||||||
|
|
||||||
|
public final StringPath company = createString("company");
|
||||||
|
|
||||||
|
public final NumberPath<Integer> id = createNumber("id", Integer.class);
|
||||||
|
|
||||||
|
public final StringPath symbol = createString("symbol");
|
||||||
|
|
||||||
|
public QOptionalStockPO(String variable) {
|
||||||
|
super(OptionalStockPO.class, forVariable(variable));
|
||||||
|
}
|
||||||
|
|
||||||
|
public QOptionalStockPO(Path<? extends OptionalStockPO> path) {
|
||||||
|
super(path.getType(), path.getMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
public QOptionalStockPO(PathMetadata metadata) {
|
||||||
|
super(OptionalStockPO.class, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package cn.stock.market.domain.basic.convert;
|
||||||
|
|
||||||
|
import cn.qutaojing.common.domain.convert.SimpleEntityPOConvert;
|
||||||
|
import cn.qutaojing.common.utils.SpringUtils;
|
||||||
|
import cn.stock.market.domain.basic.entity.OptionalStock;
|
||||||
|
import cn.stock.market.infrastructure.db.po.OptionalStockPO;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
@Lazy
|
||||||
|
public class OptionalStockConvert extends SimpleEntityPOConvert<OptionalStock, OptionalStockPO> {
|
||||||
|
public static OptionalStockConvert of() {
|
||||||
|
return SpringUtils.getBean(OptionalStockConvert.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package cn.stock.market.domain.basic.entity;
|
||||||
|
|
||||||
|
import cn.stock.market.infrastructure.db.po.OptionalStockPO;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@EqualsAndHashCode(
|
||||||
|
callSuper = false
|
||||||
|
)
|
||||||
|
public class OptionalStock extends OptionalStockPO {
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package cn.stock.market.domain.basic.repository;
|
||||||
|
|
||||||
|
import cn.qutaojing.common.domain.convert.IEntityPOConvert;
|
||||||
|
import cn.qutaojing.common.domain.respostory.SimplePoConvertEntityRepository;
|
||||||
|
import cn.stock.market.domain.basic.convert.OptionalStockConvert;
|
||||||
|
import cn.stock.market.domain.basic.entity.OptionalStock;
|
||||||
|
import cn.stock.market.infrastructure.db.po.OptionalStockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.repo.OptionalStockRepo;
|
||||||
|
import com.rp.spring.jpa.GenericJpaRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor(
|
||||||
|
onConstructor = @__(@Autowired)
|
||||||
|
)
|
||||||
|
public class OptionalStockRepository extends SimplePoConvertEntityRepository<OptionalStock, OptionalStockPO, Integer> {
|
||||||
|
final OptionalStockRepo repo;
|
||||||
|
|
||||||
|
final OptionalStockConvert convert;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GenericJpaRepository<OptionalStockPO, Integer> repo() {
|
||||||
|
return repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEntityPOConvert<OptionalStock, OptionalStockPO> convert() {
|
||||||
|
return convert;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -249,10 +249,17 @@ public class StockService {
|
|||||||
String result = "";
|
String result = "";
|
||||||
try {
|
try {
|
||||||
// 使用Jsoup连接到网页
|
// 使用Jsoup连接到网页
|
||||||
Document doc = Jsoup.connect("https://www.business-standard.com/markets/news")
|
// Document doc = Jsoup.connect("https://www.business-standard.com/markets/news")
|
||||||
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36")
|
// .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36")
|
||||||
.header("Referer", "https://www.business-standard.com/")
|
// .header("Referer", "https://www.business-standard.com/")
|
||||||
|
// .header("Accept-Language", "en-US,en;q=0.9")
|
||||||
|
// .get();
|
||||||
|
String url = "https://www.business-standard.com/markets/news";
|
||||||
|
Document doc = Jsoup.connect(url)
|
||||||
|
.referrer("https://www.business-standard.com/")
|
||||||
.header("Accept-Language", "en-US,en;q=0.9")
|
.header("Accept-Language", "en-US,en;q=0.9")
|
||||||
|
.userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1")
|
||||||
|
.timeout(5000) // timeout 5 seconds
|
||||||
.get();
|
.get();
|
||||||
// result = doc.html().substring(doc.html().indexOf("<div class=\"listingstyle_shortvideoimg__0TWuX shortvideoimg\">"),doc.html().lastIndexOf("<div class=\"listingstyle_shortvideoimg__0TWuX shortvideoimg\">")+500);
|
// result = doc.html().substring(doc.html().indexOf("<div class=\"listingstyle_shortvideoimg__0TWuX shortvideoimg\">"),doc.html().lastIndexOf("<div class=\"listingstyle_shortvideoimg__0TWuX shortvideoimg\">")+500);
|
||||||
Elements divElements = doc.select("div.listingstyle_cardlistlist__dfq57");
|
Elements divElements = doc.select("div.listingstyle_cardlistlist__dfq57");
|
||||||
@@ -272,10 +279,16 @@ public class StockService {
|
|||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
try {
|
try {
|
||||||
// 使用Jsoup连接到网页
|
// 使用Jsoup连接到网页
|
||||||
|
// Document doc = Jsoup.connect(url)
|
||||||
|
// .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36")
|
||||||
|
// .header("Referer", "https://www.business-standard.com/")
|
||||||
|
// .header("Accept-Language", "en-US,en;q=0.9")
|
||||||
|
// .get();
|
||||||
Document doc = Jsoup.connect(url)
|
Document doc = Jsoup.connect(url)
|
||||||
.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36")
|
.referrer("https://www.business-standard.com/")
|
||||||
.header("Referer", "https://www.business-standard.com/")
|
|
||||||
.header("Accept-Language", "en-US,en;q=0.9")
|
.header("Accept-Language", "en-US,en;q=0.9")
|
||||||
|
.userAgent("Mozilla/5.0 (iPhone; CPU iPhone OS 16_6 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.6 Mobile/15E148 Safari/604.1")
|
||||||
|
.timeout(5000) // timeout 5 seconds
|
||||||
.get();
|
.get();
|
||||||
result = doc.html().substring(doc.html().indexOf("articleBody") + 14, doc.html().indexOf(",\"author\":") - 1);
|
result = doc.html().substring(doc.html().indexOf("articleBody") + 14, doc.html().indexOf(",\"author\":") - 1);
|
||||||
list.add(result);
|
list.add(result);
|
||||||
|
|||||||
18
src/main/java/cn/stock/market/dto/OptionalStockResponse.java
Normal file
18
src/main/java/cn/stock/market/dto/OptionalStockResponse.java
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
package cn.stock.market.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class OptionalStockResponse {
|
||||||
|
private String message;
|
||||||
|
private Integer code;
|
||||||
|
private DataResponse data = new DataResponse();
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public static class DataResponse {
|
||||||
|
private String symbol;
|
||||||
|
private String company;
|
||||||
|
private Double pricecurrent;
|
||||||
|
private Float pricepercentchange;
|
||||||
|
}
|
||||||
|
}
|
||||||
48
src/main/java/cn/stock/market/dto/query/StockChartDto.java
Normal file
48
src/main/java/cn/stock/market/dto/query/StockChartDto.java
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
package cn.stock.market.dto.query;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class StockChartDto {
|
||||||
|
private Long timestamp;
|
||||||
|
private double open;
|
||||||
|
private double high;
|
||||||
|
private double low;
|
||||||
|
private double close;
|
||||||
|
private double volume;
|
||||||
|
|
||||||
|
public StockChartDto(Long date, double open, double high, double low, double close, double volume) {
|
||||||
|
this.timestamp = date;
|
||||||
|
this.open = open;
|
||||||
|
this.high = high;
|
||||||
|
this.low = low;
|
||||||
|
this.close = close;
|
||||||
|
this.volume = volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getVolume() {
|
||||||
|
return volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getTimestamp() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getOpen() {
|
||||||
|
return open;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getHigh() {
|
||||||
|
return high;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getLow() {
|
||||||
|
return low;
|
||||||
|
}
|
||||||
|
|
||||||
|
public double getClose() {
|
||||||
|
return close;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package cn.stock.market.infrastructure.db.po;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
import org.hibernate.annotations.DynamicInsert;
|
||||||
|
import org.hibernate.annotations.DynamicUpdate;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@DynamicInsert
|
||||||
|
@DynamicUpdate
|
||||||
|
@Table(
|
||||||
|
name = "optional_stock"
|
||||||
|
)
|
||||||
|
public class OptionalStockPO {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(
|
||||||
|
strategy = javax.persistence.GenerationType.IDENTITY
|
||||||
|
)
|
||||||
|
Integer id;
|
||||||
|
|
||||||
|
String symbol;
|
||||||
|
|
||||||
|
String company;
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
package cn.stock.market.infrastructure.db.repo;
|
||||||
|
|
||||||
|
import cn.stock.market.infrastructure.db.po.OptionalStockPO;
|
||||||
|
import com.rp.spring.jpa.GenericJpaRepository;
|
||||||
|
|
||||||
|
public interface OptionalStockRepo extends GenericJpaRepository<OptionalStockPO, Integer> {
|
||||||
|
}
|
||||||
@@ -3,14 +3,21 @@ package cn.stock.market.web;
|
|||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
import cn.stock.market.MoneyStockSuggestDTO;
|
import cn.stock.market.MoneyStockSuggestDTO;
|
||||||
import cn.stock.market.domain.basic.entity.MoneyStock;
|
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.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.StockHistoryRequest;
|
||||||
import cn.stock.market.dto.StockHistoryResponse;
|
import cn.stock.market.dto.StockHistoryResponse;
|
||||||
|
import cn.stock.market.dto.query.StockChartDto;
|
||||||
import cn.stock.market.infrastructure.db.po.QMoneyStockPO;
|
import cn.stock.market.infrastructure.db.po.QMoneyStockPO;
|
||||||
|
import cn.stock.market.utils.HttpRequest;
|
||||||
import cn.stock.market.utils.NseIndiaRequest;
|
import cn.stock.market.utils.NseIndiaRequest;
|
||||||
import cn.stock.market.utils.ServerResponse;
|
import cn.stock.market.utils.ServerResponse;
|
||||||
import cn.stock.market.web.annotations.EncryptFilter;
|
import cn.stock.market.web.annotations.EncryptFilter;
|
||||||
import com.alibaba.fastjson.JSONObject;
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import com.fasterxml.jackson.databind.JsonNode;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.google.common.cache.Cache;
|
import com.google.common.cache.Cache;
|
||||||
import com.google.common.cache.CacheBuilder;
|
import com.google.common.cache.CacheBuilder;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
@@ -23,6 +30,12 @@ import io.swagger.annotations.ApiResponses;
|
|||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.collections.CollectionUtils;
|
import org.apache.commons.collections.CollectionUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.apache.http.HttpResponse;
|
||||||
|
import org.apache.http.client.ClientProtocolException;
|
||||||
|
import org.apache.http.client.methods.HttpGet;
|
||||||
|
import org.apache.http.impl.client.CloseableHttpClient;
|
||||||
|
import org.apache.http.impl.client.HttpClients;
|
||||||
|
import org.apache.http.util.EntityUtils;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
import org.jsoup.nodes.Document;
|
import org.jsoup.nodes.Document;
|
||||||
import org.jsoup.nodes.Element;
|
import org.jsoup.nodes.Element;
|
||||||
@@ -36,8 +49,16 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.client.RestClientException;
|
import org.springframework.web.client.RestClientException;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
import org.springframework.web.util.UriUtils;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.net.URLEncoder;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.YearMonth;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -58,7 +79,14 @@ public class MoneyApiController {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private MoneyStockRepository moneyStockRepository;
|
private MoneyStockRepository moneyStockRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OptionalStockRepository optionalStockRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
private static final String EXTERNAL_API_URL = "https://priceapi.moneycontrol.com/techCharts/indianMarket/stock/history";
|
private static final String EXTERNAL_API_URL = "https://priceapi.moneycontrol.com/techCharts/indianMarket/stock/history";
|
||||||
|
private static final String OPTIONAL_STOCK_MONEYCONTROL_URL = "https://priceapi.moneycontrol.com/pricefeed/notapplicable/inidicesindia/";
|
||||||
|
|
||||||
@ApiOperation(value = "股票详情信息", httpMethod = "GET")
|
@ApiOperation(value = "股票详情信息", httpMethod = "GET")
|
||||||
@ApiImplicitParams({
|
@ApiImplicitParams({
|
||||||
@@ -690,26 +718,26 @@ public class MoneyApiController {
|
|||||||
Long to = null;
|
Long to = null;
|
||||||
Long from = null;
|
Long from = null;
|
||||||
int countback = 5;
|
int countback = 5;
|
||||||
if (StringUtils.equals("H", resolution)) {
|
if(StringUtils.equals("H",resolution)){
|
||||||
to = (long) (System.currentTimeMillis() / 1000);
|
to = (long) (System.currentTimeMillis() / 1000);
|
||||||
from = to - (60 * 60);
|
from = to - (10 * 60 * 60 );
|
||||||
countback = 60;
|
countback = 328;
|
||||||
request.setResolution("1");
|
request.setResolution("60");
|
||||||
} else if (StringUtils.equals("D", resolution)) {
|
}else if(StringUtils.equals("D",resolution)){
|
||||||
to = (long) (System.currentTimeMillis() / 1000);
|
to = (long) (System.currentTimeMillis() / 1000);
|
||||||
from = to - (24 * 60 * 60);
|
from = to - (2 * 30 * 24 * 60 * 60 );
|
||||||
countback = 390;
|
countback = 730;
|
||||||
request.setResolution("1");
|
request.setResolution("1D");
|
||||||
} else if (StringUtils.equals("W", resolution)) {
|
} else if (StringUtils.equals("W", resolution)) {
|
||||||
to = (long) (System.currentTimeMillis() / 1000);
|
to = (long) (System.currentTimeMillis() / 1000);
|
||||||
from = to - (7 * 24 * 60 * 60);
|
from = to - (7 * 24 * 60 * 60);
|
||||||
countback = 471;
|
countback = 730;
|
||||||
request.setResolution("5");
|
request.setResolution("1W");
|
||||||
} else if (StringUtils.equals("M", resolution)) {
|
} else if (StringUtils.equals("M", resolution)) {
|
||||||
to = (long) (System.currentTimeMillis() / 1000);
|
to = (long) (System.currentTimeMillis() / 1000);
|
||||||
from = to - (35 * 24 * 60 * 60);
|
from = to - (15 * 30 * 24 * 60 * 60);
|
||||||
countback = 328;
|
countback = 730;
|
||||||
request.setResolution("30");
|
request.setResolution("1D");
|
||||||
}
|
}
|
||||||
|
|
||||||
request.setFrom(from);
|
request.setFrom(from);
|
||||||
@@ -724,7 +752,81 @@ public class MoneyApiController {
|
|||||||
|
|
||||||
while (response == null && retryCount < maxRetries) {
|
while (response == null && retryCount < maxRetries) {
|
||||||
try {
|
try {
|
||||||
response = restTemplate.getForObject(apiUrl, StockHistoryResponse.class);
|
if (StringUtils.equals("M", resolution)) {
|
||||||
|
CloseableHttpClient client = HttpClients.createDefault();
|
||||||
|
HttpGet req = new HttpGet(apiUrl);
|
||||||
|
HttpResponse resp = client.execute(req);
|
||||||
|
String jsonResponse = EntityUtils.toString(resp.getEntity(), "UTF-8");
|
||||||
|
ObjectMapper mapper = new ObjectMapper();
|
||||||
|
JsonNode rootNode = mapper.readTree(jsonResponse);
|
||||||
|
|
||||||
|
JsonNode timeNode = rootNode.get("t");
|
||||||
|
JsonNode lowNode = rootNode.get("l");
|
||||||
|
JsonNode highNode = rootNode.get("h");
|
||||||
|
JsonNode openNode = rootNode.get("o");
|
||||||
|
JsonNode closeNode = rootNode.get("c");
|
||||||
|
JsonNode volumeNote = rootNode.get("v");
|
||||||
|
|
||||||
|
List<StockChartDto> stocks = new ArrayList<>();
|
||||||
|
for (int i = 0; i < timeNode.size(); i++) {
|
||||||
|
long timestamp = timeNode.get(i).asLong();
|
||||||
|
double closePrice = closeNode.get(i).asDouble();
|
||||||
|
double openPrice = openNode.get(i).asDouble();
|
||||||
|
double volume = volumeNote.get(i).asDouble();
|
||||||
|
double low = lowNode.get(i).asDouble();
|
||||||
|
double high = highNode.get(i).asDouble();
|
||||||
|
|
||||||
|
stocks.add(new StockChartDto(timestamp, openPrice, high, low, closePrice, volume));
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, List<StockChartDto>> groupedByMonth = stocks.stream()
|
||||||
|
.collect(Collectors.groupingBy(
|
||||||
|
sp -> Instant.ofEpochSecond(sp.getTimestamp())
|
||||||
|
.atZone(ZoneId.systemDefault())
|
||||||
|
.toLocalDate()
|
||||||
|
.format(DateTimeFormatter.ofPattern("yyyy-MM")),
|
||||||
|
LinkedHashMap::new,
|
||||||
|
Collectors.toList()
|
||||||
|
));
|
||||||
|
|
||||||
|
List<Long> timestamps = new ArrayList<>();
|
||||||
|
List<Double> opens = new ArrayList<>();
|
||||||
|
List<Double> closes = new ArrayList<>();
|
||||||
|
List<Double> highs = new ArrayList<>();
|
||||||
|
List<Double> lows = new ArrayList<>();
|
||||||
|
List<Long> volumes = new ArrayList<>();
|
||||||
|
|
||||||
|
response = new StockHistoryResponse();
|
||||||
|
groupedByMonth.forEach((month, prices) -> {
|
||||||
|
double open = prices.get(0).getOpen();
|
||||||
|
double close = prices.get(prices.size() - 1).getClose();
|
||||||
|
double high = prices.stream().mapToDouble(StockChartDto::getHigh).max().orElse(0);
|
||||||
|
double low = prices.stream().mapToDouble(StockChartDto::getLow).min().orElse(0);
|
||||||
|
double volume = prices.stream().mapToDouble(StockChartDto::getVolume).sum();
|
||||||
|
|
||||||
|
long timestamp = YearMonth.parse(month, DateTimeFormatter.ofPattern("yyyy-MM")).atDay(1).atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli() / 1000;
|
||||||
|
timestamps.add(timestamp);
|
||||||
|
opens.add(open);
|
||||||
|
closes.add(close);
|
||||||
|
highs.add(high);
|
||||||
|
lows.add(low);
|
||||||
|
volumes.add((long) volume);
|
||||||
|
|
||||||
|
System.out.println("Month: " + month);
|
||||||
|
System.out.println("Open: " + open + ", Close: " + close + ", High: " + high + ", Low: " + low);
|
||||||
|
});
|
||||||
|
|
||||||
|
response.setS("ok");
|
||||||
|
response.setT(timestamps);
|
||||||
|
response.setL(lows);
|
||||||
|
response.setH(highs);
|
||||||
|
response.setO(opens);
|
||||||
|
response.setC(closes);
|
||||||
|
response.setV(volumes);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
response = restTemplate.getForObject(apiUrl, StockHistoryResponse.class);
|
||||||
|
}
|
||||||
} catch (RestClientException e) {
|
} catch (RestClientException e) {
|
||||||
// Log the exception or perform any other error handling
|
// Log the exception or perform any other error handling
|
||||||
log.error("Error while making API request. Retrying... (Retry count: {})", retryCount + 1);
|
log.error("Error while making API request. Retrying... (Retry count: {})", retryCount + 1);
|
||||||
@@ -737,11 +839,15 @@ public class MoneyApiController {
|
|||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
Thread.currentThread().interrupt();
|
Thread.currentThread().interrupt();
|
||||||
}
|
}
|
||||||
|
} catch (ClientProtocolException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response != null && !response.getS().equals("error")) {
|
if (response != null && !response.getS().equals("error")) {
|
||||||
setResponse(response, resolution);
|
// setResponse(response, resolution);
|
||||||
// API request successful, return the response
|
// API request successful, return the response
|
||||||
return ResponseEntity.ok(response);
|
return ResponseEntity.ok(response);
|
||||||
} else {
|
} else {
|
||||||
@@ -768,6 +874,33 @@ public class MoneyApiController {
|
|||||||
// 返回响应
|
// 返回响应
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@GetMapping({"/market/api/market/stock/optional", "/api/market/stock/optional"})
|
||||||
|
@ResponseBody
|
||||||
|
@EncryptFilter(decryptRequest = false)
|
||||||
|
public ResponseEntity<List<Object>> getOptionalStock() {
|
||||||
|
List<OptionalStock> optionalStocks = optionalStockRepository.findAll();
|
||||||
|
List<Object> data = optionalStocks.stream().map(stock -> {
|
||||||
|
try {
|
||||||
|
String responseStr = HttpRequest.doGrabGet(OPTIONAL_STOCK_MONEYCONTROL_URL + URLEncoder.encode(stock.getSymbol(), "UTF-8"));
|
||||||
|
OptionalStockResponse response = objectMapper.readValue(responseStr, OptionalStockResponse.class);
|
||||||
|
if (response != null && response.getCode().equals(200)) {
|
||||||
|
return response.getData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e) {
|
||||||
|
log.error("Failed to get optional stock from moneycontrol for " + stock.getSymbol(), e);
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionalStockResponse response = new OptionalStockResponse();
|
||||||
|
response.getData().setSymbol(stock.getSymbol());
|
||||||
|
response.getData().setSymbol(stock.getCompany());
|
||||||
|
|
||||||
|
return response.getData();
|
||||||
|
}).collect(Collectors.toList());
|
||||||
|
|
||||||
|
return ResponseEntity.ok(data);
|
||||||
|
}
|
||||||
|
|
||||||
private void setResponse(StockHistoryResponse response, String resolution) {
|
private void setResponse(StockHistoryResponse response, String resolution) {
|
||||||
if (!"ok".equals(response.getS())) {
|
if (!"ok".equals(response.getS())) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
Reference in New Issue
Block a user