update new stock
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -89,6 +89,12 @@
|
|||||||
<version>4.1.0</version>
|
<version>4.1.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.json</groupId>
|
||||||
|
<artifactId>json</artifactId>
|
||||||
|
<version>20240303</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.springfox</groupId>
|
<groupId>io.springfox</groupId>
|
||||||
<artifactId>springfox-swagger2</artifactId>
|
<artifactId>springfox-swagger2</artifactId>
|
||||||
|
|||||||
@@ -29,6 +29,10 @@ public class QMoneyStockPO extends EntityPathBase<MoneyStockPO> {
|
|||||||
|
|
||||||
public final StringPath moneyScId = createString("moneyScId");
|
public final StringPath moneyScId = createString("moneyScId");
|
||||||
|
|
||||||
|
public final StringPath nseIndiaChartId = createString("nseIndiaChartId");
|
||||||
|
|
||||||
|
public final StringPath nseIndiaId = createString("nseIndiaId");
|
||||||
|
|
||||||
public final DateTimePath<java.util.Date> saveTime = createDateTime("saveTime", java.util.Date.class);
|
public final DateTimePath<java.util.Date> saveTime = createDateTime("saveTime", java.util.Date.class);
|
||||||
|
|
||||||
public final StringPath selfDispId = createString("selfDispId");
|
public final StringPath selfDispId = createString("selfDispId");
|
||||||
@@ -39,6 +43,8 @@ public class QMoneyStockPO extends EntityPathBase<MoneyStockPO> {
|
|||||||
|
|
||||||
public final StringPath stockType = createString("stockType");
|
public final StringPath stockType = createString("stockType");
|
||||||
|
|
||||||
|
public final BooleanPath useFromBseindia = createBoolean("useFromBseindia");
|
||||||
|
|
||||||
public QMoneyStockPO(String variable) {
|
public QMoneyStockPO(String variable) {
|
||||||
super(MoneyStockPO.class, forVariable(variable));
|
super(MoneyStockPO.class, forVariable(variable));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,8 @@ public class QStockIpoPO extends EntityPathBase<StockIpoPO> {
|
|||||||
|
|
||||||
public final DateTimePath<java.util.Date> createDate = createDateTime("createDate", java.util.Date.class);
|
public final DateTimePath<java.util.Date> createDate = createDateTime("createDate", java.util.Date.class);
|
||||||
|
|
||||||
|
public final StringPath exchangeType = createString("exchangeType");
|
||||||
|
|
||||||
public final NumberPath<Integer> id = createNumber("id", Integer.class);
|
public final NumberPath<Integer> id = createNumber("id", Integer.class);
|
||||||
|
|
||||||
public final NumberPath<Integer> isList = createNumber("isList", Integer.class);
|
public final NumberPath<Integer> isList = createNumber("isList", Integer.class);
|
||||||
@@ -38,7 +40,6 @@ public class QStockIpoPO extends EntityPathBase<StockIpoPO> {
|
|||||||
public final StringPath stockCode = createString("stockCode");
|
public final StringPath stockCode = createString("stockCode");
|
||||||
|
|
||||||
public final StringPath stockName = createString("stockName");
|
public final StringPath stockName = createString("stockName");
|
||||||
public final StringPath exchangeType = createString("exchangeType");
|
|
||||||
|
|
||||||
public final NumberPath<java.math.BigDecimal> stockPrice = createNumber("stockPrice", java.math.BigDecimal.class);
|
public final NumberPath<java.math.BigDecimal> stockPrice = createNumber("stockPrice", java.math.BigDecimal.class);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
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;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* QStockTempPO is a Querydsl query type for StockTempPO
|
||||||
|
*/
|
||||||
|
@Generated("com.querydsl.codegen.EntitySerializer")
|
||||||
|
public class QStockTempPO extends EntityPathBase<StockTempPO> {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1973569078L;
|
||||||
|
|
||||||
|
public static final QStockTempPO stockTempPO = new QStockTempPO("stockTempPO");
|
||||||
|
|
||||||
|
public final NumberPath<Integer> id = createNumber("id", Integer.class);
|
||||||
|
|
||||||
|
public final StringPath stockGid = createString("stockGid");
|
||||||
|
|
||||||
|
public final StringPath stockLogo = createString("stockLogo");
|
||||||
|
|
||||||
|
public final StringPath stockType = createString("stockType");
|
||||||
|
|
||||||
|
public QStockTempPO(String variable) {
|
||||||
|
super(StockTempPO.class, forVariable(variable));
|
||||||
|
}
|
||||||
|
|
||||||
|
public QStockTempPO(Path<? extends StockTempPO> path) {
|
||||||
|
super(path.getType(), path.getMetadata());
|
||||||
|
}
|
||||||
|
|
||||||
|
public QStockTempPO(PathMetadata metadata) {
|
||||||
|
super(StockTempPO.class, metadata);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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.Stock;
|
||||||
|
import cn.stock.market.domain.basic.entity.StockTemp;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockTempPO;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StockConvert
|
||||||
|
*
|
||||||
|
* @author rplees
|
||||||
|
* @email rplees.i.ly@gmail.com
|
||||||
|
* @created 2023/06/17
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@Lazy
|
||||||
|
public class StockTempConvert extends SimpleEntityPOConvert<StockTemp, StockTempPO> {
|
||||||
|
public static StockTempConvert of() {
|
||||||
|
return SpringUtils.getBean(StockTempConvert.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package cn.stock.market.domain.basic.entity;
|
||||||
|
|
||||||
|
import cn.qutaojing.common.utils.Beans;
|
||||||
|
import cn.stock.market.dto.command.StockCreateCommand;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockTempPO;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.EqualsAndHashCode;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stock
|
||||||
|
*
|
||||||
|
* @author rplees
|
||||||
|
* @email rplees.i.ly@gmail.com
|
||||||
|
* @created 2023/06/17
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@SuperBuilder
|
||||||
|
@EqualsAndHashCode(
|
||||||
|
callSuper = false
|
||||||
|
)
|
||||||
|
public class StockTemp extends StockTempPO {
|
||||||
|
}
|
||||||
@@ -55,6 +55,11 @@ public class StockRepository extends LocalCacheRepository<Stock, StockPO, Intege
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Stock> cacheGidMap() {
|
||||||
|
Map<String, Stock> map = cacheList().stream().collect(Collectors.toMap(Stock::getStockGid, val -> val, (u, v) -> u));
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
public Map<String, Stock> cacheNameMap() {
|
public Map<String, Stock> cacheNameMap() {
|
||||||
Map<String, Stock> map = cacheList()
|
Map<String, Stock> map = cacheList()
|
||||||
.stream().collect(Collectors.toMap(Stock::getStockName, val -> val, (u, v) -> u));
|
.stream().collect(Collectors.toMap(Stock::getStockName, val -> val, (u, v) -> u));
|
||||||
|
|||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package cn.stock.market.domain.basic.repository;
|
||||||
|
|
||||||
|
import cn.qutaojing.common.domain.convert.IEntityPOConvert;
|
||||||
|
import cn.qutaojing.common.domain.respostory.LocalCacheBean;
|
||||||
|
import cn.qutaojing.common.domain.respostory.LocalCacheRepository;
|
||||||
|
import cn.qutaojing.common.jpa.ConditionBuilder;
|
||||||
|
import cn.qutaojing.common.utils.SpringUtils;
|
||||||
|
import cn.stock.market.domain.basic.convert.StockConvert;
|
||||||
|
import cn.stock.market.domain.basic.convert.StockTempConvert;
|
||||||
|
import cn.stock.market.domain.basic.entity.Stock;
|
||||||
|
import cn.stock.market.domain.basic.entity.StockTemp;
|
||||||
|
import cn.stock.market.infrastructure.db.po.QStockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.QStockTempPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockTempPO;
|
||||||
|
import cn.stock.market.infrastructure.db.repo.StockRepo;
|
||||||
|
import cn.stock.market.infrastructure.db.repo.StockTempRepo;
|
||||||
|
import com.google.common.cache.CacheBuilder;
|
||||||
|
import com.rp.spring.jpa.GenericJpaRepository;
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.data.domain.Page;
|
||||||
|
import org.springframework.data.domain.Pageable;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StockRepository
|
||||||
|
*
|
||||||
|
* @author rplees
|
||||||
|
* @email rplees.i.ly@gmail.com
|
||||||
|
* @created 2023/06/17
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
|
||||||
|
public class StockTempRepository extends LocalCacheRepository<StockTemp, StockTempPO, Integer> {
|
||||||
|
final StockTempRepo repo;
|
||||||
|
final StockTempConvert convert;
|
||||||
|
final static QStockTempPO q = QStockTempPO.stockTempPO;
|
||||||
|
|
||||||
|
public List<StockTemp> findAllForCheck() {
|
||||||
|
return findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GenericJpaRepository<StockTempPO, Integer> repo() {
|
||||||
|
return repo;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IEntityPOConvert<StockTemp, StockTempPO> convert() {
|
||||||
|
return convert;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static StockTempRepository of() {
|
||||||
|
return SpringUtils.getBean(StockTempRepository.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
src/main/java/cn/stock/market/dto/model/Symbol.java
Normal file
28
src/main/java/cn/stock/market/dto/model/Symbol.java
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package cn.stock.market.dto.model;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
public class Symbol {
|
||||||
|
private String symbol;
|
||||||
|
private String description;
|
||||||
|
private String stockGid;
|
||||||
|
private String type;
|
||||||
|
private String exchange;
|
||||||
|
private String currencyCode;
|
||||||
|
private String currencyLogoid;
|
||||||
|
private String logoid;
|
||||||
|
private String providerId;
|
||||||
|
private String sourceLogoid;
|
||||||
|
private String sourceId;
|
||||||
|
private String country;
|
||||||
|
private boolean isPrimaryListing;
|
||||||
|
private List<String> typespecs;
|
||||||
|
|
||||||
|
// Getters and setters
|
||||||
|
// Bạn có thể dùng Lombok nếu muốn ngắn gọn hơn
|
||||||
|
// Hoặc generate getter/setter trong IDE
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
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.*;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StockPO
|
||||||
|
*
|
||||||
|
* @author rplees
|
||||||
|
* @email rplees.i.ly@gmail.com
|
||||||
|
* @created 2023/06/17
|
||||||
|
*/
|
||||||
|
@SuperBuilder
|
||||||
|
@Data
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Entity
|
||||||
|
@DynamicInsert
|
||||||
|
@DynamicUpdate
|
||||||
|
@Table(name = "stockTemp")
|
||||||
|
public class StockTempPO {
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
Integer id;
|
||||||
|
|
||||||
|
String stockType;
|
||||||
|
|
||||||
|
String stockGid;
|
||||||
|
|
||||||
|
String stockLogo;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package cn.stock.market.infrastructure.db.repo;
|
||||||
|
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockPO;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockTempPO;
|
||||||
|
import com.rp.spring.jpa.GenericJpaRepository;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* StockRepo
|
||||||
|
*
|
||||||
|
* @author rplees
|
||||||
|
* @email rplees.i.ly@gmail.com
|
||||||
|
* @created 2023/06/17
|
||||||
|
*/
|
||||||
|
public interface StockTempRepo extends GenericJpaRepository<StockTempPO, Integer> {
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
package cn.stock.market.infrastructure.job;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.net.HttpURLConnection;
|
||||||
|
import java.net.URL;
|
||||||
|
import java.util.*;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import cn.stock.market.domain.basic.entity.Stock;
|
||||||
|
import cn.stock.market.domain.basic.entity.StockTemp;
|
||||||
|
import cn.stock.market.domain.basic.repository.StockRepository;
|
||||||
|
import cn.stock.market.domain.basic.repository.StockTempRepository;
|
||||||
|
import cn.stock.market.dto.model.Symbol;
|
||||||
|
import cn.stock.market.infrastructure.db.po.StockPO;
|
||||||
|
import okhttp3.OkHttpClient;
|
||||||
|
import okhttp3.Request;
|
||||||
|
import okhttp3.Response;
|
||||||
|
import org.json.*;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
|
@Component
|
||||||
|
public class StockNewTask {
|
||||||
|
private static final OkHttpClient client = new OkHttpClient();
|
||||||
|
private static final String BASE_URL = "https://symbol-search.tradingview.com/symbol_search/v3/";
|
||||||
|
private static final String PARAMS = "?start={start}&hl=1&country=DE&lang=en&search_type=stocks&domain=production&sort_by_country=US&promo=true&exchange={exchange}";
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
StockRepository stockRepository;
|
||||||
|
|
||||||
|
|
||||||
|
// @PostConstruct
|
||||||
|
@Scheduled(cron = "0 01 22 * * ?")
|
||||||
|
public void syncStock() throws Exception {
|
||||||
|
|
||||||
|
int limit = 20000;
|
||||||
|
List<String> exchanges = Arrays.asList("BER", "DUS", "HAM", "HAN", "MUN", "SWB", "FWB", "XETR");
|
||||||
|
Map<String, Stock> stockGidMap = stockRepository.cacheGidMap();
|
||||||
|
for (String exchange : exchanges) {
|
||||||
|
List<Stock> newStocks = new ArrayList<>();
|
||||||
|
int start = 0;
|
||||||
|
int symbolsRemaining;
|
||||||
|
do {
|
||||||
|
int finalStart = start;
|
||||||
|
if(start > 0){
|
||||||
|
finalStart = start + 1;
|
||||||
|
}
|
||||||
|
String url = BASE_URL + PARAMS.replace("{start}", String.valueOf(finalStart)).replace("{exchange}", exchange);
|
||||||
|
Request request = new Request.Builder()
|
||||||
|
.url(url)
|
||||||
|
.addHeader("Origin", "https://www.tradingview.com")
|
||||||
|
.addHeader("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)")
|
||||||
|
.addHeader("Accept", "application/json, text/plain, */*")
|
||||||
|
.addHeader("Referer", "https://www.tradingview.com/")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
Response response = client.newCall(request).execute();
|
||||||
|
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
throw new RuntimeException("Unexpected response code: " + response.code());
|
||||||
|
}
|
||||||
|
|
||||||
|
String responseBody = response.body().string();
|
||||||
|
JSONObject json = new JSONObject(responseBody);
|
||||||
|
JSONArray symbols = json.getJSONArray("symbols");
|
||||||
|
symbolsRemaining = json.getInt("symbols_remaining");
|
||||||
|
|
||||||
|
for (int i = 0; i < symbols.length(); i++) {
|
||||||
|
JSONObject s = symbols.getJSONObject(i);
|
||||||
|
if (s.optString("type").equals("stock") && !stockGidMap.containsKey(s.optString("exchange") + ":" + s.getString("symbol"))) {
|
||||||
|
Stock stock = new Stock();
|
||||||
|
stock.setStockGid(s.optString("exchange") + ":" +s.getString("symbol"));
|
||||||
|
stock.setStockCode(stock.getStockGid());
|
||||||
|
stock.setStockSpell(s.optString("symbol"));
|
||||||
|
stock.setStockName(s.optString("description"));
|
||||||
|
stock.setStockSymbol(s.optString("symbol"));
|
||||||
|
stock.setStockType(s.optString("exchange"));
|
||||||
|
stock.setIsLock(0);
|
||||||
|
stock.setIsShow(0);
|
||||||
|
stock.setAddTime(new Date());
|
||||||
|
stock.setStockState(0);
|
||||||
|
stock.setStockPlate("https://s3-symbol-logo.tradingview.com/" + s.optString("source_logoid") + "--big.svg");
|
||||||
|
newStocks.add(stock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Thread.sleep(500);
|
||||||
|
|
||||||
|
start += symbols.length();
|
||||||
|
System.out.println("Fetched: " + symbols.length() + ", Remaining: " + symbolsRemaining);
|
||||||
|
if (!newStocks.isEmpty()) {
|
||||||
|
stockRepository.saveAll(newStocks);
|
||||||
|
}
|
||||||
|
if (start >= limit) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} while (symbolsRemaining > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user