diff --git a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Daily.java b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Daily.java index 9f263e2..9a74566 100644 --- a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Daily.java +++ b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Daily.java @@ -29,6 +29,7 @@ import org.springframework.data.jpa.domain.support.AuditingEntityListener; @Table(name = Constants.DATABASE_PREFIX + "daily") public class Daily extends SimpleEntity { @Column(nullable = false) + @Comment("交易日") private LocalDate tradeDate; @Comment("开盘价") private Double open; diff --git a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Stock.java b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Stock.java index 50a4707..076b6e2 100644 --- a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Stock.java +++ b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Stock.java @@ -61,6 +61,10 @@ public class Stock extends SimpleEntity { @ToString.Exclude private Set dailies; + @OneToMany(mappedBy = "stock", cascade = CascadeType.REMOVE) + @ToString.Exclude + private Set yearlies; + @OneToMany(mappedBy = "stock", cascade = CascadeType.REMOVE) @ToString.Exclude private Set indicators; diff --git a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Yearly.java b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Yearly.java new file mode 100644 index 0000000..e697dd5 --- /dev/null +++ b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/entity/Yearly.java @@ -0,0 +1,57 @@ +package com.lanyuanxiaoyao.leopard.core.entity; + +import com.lanyuanxiaoyao.leopard.core.Constants; +import com.lanyuanxiaoyao.service.template.entity.SimpleEntity; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EntityListeners; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.experimental.FieldNameConstants; +import org.hibernate.annotations.Comment; +import org.hibernate.annotations.DynamicInsert; +import org.hibernate.annotations.DynamicUpdate; +import org.springframework.data.jpa.domain.support.AuditingEntityListener; + +/** + * 年线行情,后复权 + */ +@Setter +@Getter +@ToString(callSuper = true) +@FieldNameConstants +@Entity +@DynamicUpdate +@DynamicInsert +@EntityListeners(AuditingEntityListener.class) +@Table(name = Constants.DATABASE_PREFIX + "yearly") +public class Yearly extends SimpleEntity { + @Column(nullable = false) + @Comment("年份") + private Integer year; + @Comment("开盘价") + private Double open; + @Comment("最高价") + private Double high; + @Comment("最低价") + private Double low; + @Comment("收盘价") + private Double close; + @Comment("涨跌额") + private Double priceChangeAmount; + @Comment("涨跌幅") + private Double priceFluctuationRange; + @Comment("成交量") + private Double volume; + @Comment("成交额") + private Double turnover; + + @ManyToOne + @JoinColumn(nullable = false) + @ToString.Exclude + private Stock stock; +} diff --git a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/DailyRepository.java b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/DailyRepository.java index 04c223c..2363a88 100644 --- a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/DailyRepository.java +++ b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/DailyRepository.java @@ -19,6 +19,14 @@ public interface DailyRepository extends SimpleRepository { @Query("select distinct daily.tradeDate from Daily daily where daily.stock.id = ?1") List findDistinctTradeDateByStockId(Long stockId); + @Query("select max(daily.tradeDate) from Daily daily") + LocalDate findMaxTradeDate(); + + @Query("select min(daily.tradeDate) from Daily daily") + LocalDate findMinTradeDate(); + + List findAllByTradeDate_YearAndStock_Code(int tradeDateYear, String stockCode); + @EntityGraph(attributePaths = {"stock"}) @Override Optional findOne(Predicate predicate); diff --git a/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/YearlyRepository.java b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/YearlyRepository.java new file mode 100644 index 0000000..bac44db --- /dev/null +++ b/leopard-core/src/main/java/com/lanyuanxiaoyao/leopard/core/repository/YearlyRepository.java @@ -0,0 +1,9 @@ +package com.lanyuanxiaoyao.leopard.core.repository; + +import com.lanyuanxiaoyao.leopard.core.entity.Yearly; +import com.lanyuanxiaoyao.service.template.repository.SimpleRepository; +import org.springframework.stereotype.Repository; + +@Repository +public interface YearlyRepository extends SimpleRepository { +} diff --git a/leopard-core/src/test/java/com/lanyuanxiaoyao/leopard/core/GenerateDDL.java b/leopard-core/src/test/java/com/lanyuanxiaoyao/leopard/core/GenerateDDL.java index ce7232c..291a4a5 100644 --- a/leopard-core/src/test/java/com/lanyuanxiaoyao/leopard/core/GenerateDDL.java +++ b/leopard-core/src/test/java/com/lanyuanxiaoyao/leopard/core/GenerateDDL.java @@ -1,6 +1,6 @@ package com.lanyuanxiaoyao.leopard.core; -import com.lanyuanxiaoyao.service.template.util.DDLGenerator; +import com.lanyuanxiaoyao.service.template.Helper; import org.hibernate.dialect.PostgreSQLDialect; import org.postgresql.Driver; @@ -12,7 +12,7 @@ import org.postgresql.Driver; */ public class GenerateDDL { public static void main(String[] args) { - DDLGenerator.generateDDL( + Helper.generateDDL( "com.lanyuanxiaoyao.leopard.core.entity", "/Users/lanyuanxiaoyao/Project/IdeaProjects/leopard/leopard-core/target", PostgreSQLDialect.class, diff --git a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDailyNode.java b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDaily.java similarity index 94% rename from leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDailyNode.java rename to leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDaily.java index 10beccd..48d5b4f 100644 --- a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDailyNode.java +++ b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/CheckDaily.java @@ -17,13 +17,13 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @LiteflowComponent("check_daily") -public class CheckDailyNode extends TaskNodeComponent { +public class CheckDaily extends TaskNodeComponent { private final StockRepository stockRepository; private final DailyRepository dailyRepository; private final TuShareService tuShareService; - public CheckDailyNode(TaskService taskService, StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService) { + public CheckDaily(TaskService taskService, StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService) { super(taskService); this.stockRepository = stockRepository; this.dailyRepository = dailyRepository; diff --git a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDailyNode.java b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDaily.java similarity index 94% rename from leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDailyNode.java rename to leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDaily.java index d89adce..7698944 100644 --- a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDailyNode.java +++ b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateDaily.java @@ -21,7 +21,7 @@ import org.springframework.transaction.support.TransactionTemplate; @Slf4j @LiteflowComponent("update_daily") -public class UpdateDailyNode extends NodeComponent { +public class UpdateDaily extends NodeComponent { private final StockRepository stockRepository; private final DailyRepository dailyRepository; @@ -29,7 +29,7 @@ public class UpdateDailyNode extends NodeComponent { private final TransactionTemplate transactionTemplate; - public UpdateDailyNode(StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService, TransactionTemplate transactionTemplate) { + public UpdateDaily(StockRepository stockRepository, DailyRepository dailyRepository, TuShareService tuShareService, TransactionTemplate transactionTemplate) { this.stockRepository = stockRepository; this.dailyRepository = dailyRepository; this.tuShareService = tuShareService; diff --git a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicatorNode.java b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicator.java similarity index 97% rename from leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicatorNode.java rename to leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicator.java index 938667f..0f92ef7 100644 --- a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicatorNode.java +++ b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateFinanceIndicator.java @@ -19,13 +19,13 @@ import lombok.extern.slf4j.Slf4j; @Slf4j @LiteflowComponent("update_finance") -public class UpdateFinanceIndicatorNode extends TaskNodeComponent { +public class UpdateFinanceIndicator extends TaskNodeComponent { private final FinanceIndicatorRepository financeIndicatorRepository; private final StockRepository stockRepository; private final TuShareService tuShareService; - protected UpdateFinanceIndicatorNode(TaskService taskService, FinanceIndicatorRepository financeIndicatorRepository, StockRepository stockRepository, TuShareService tuShareService) { + protected UpdateFinanceIndicator(TaskService taskService, FinanceIndicatorRepository financeIndicatorRepository, StockRepository stockRepository, TuShareService tuShareService) { super(taskService); this.financeIndicatorRepository = financeIndicatorRepository; this.stockRepository = stockRepository; diff --git a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStockNode.java b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStock.java similarity index 93% rename from leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStockNode.java rename to leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStock.java index 30bf05e..0897072 100644 --- a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStockNode.java +++ b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateStock.java @@ -11,12 +11,12 @@ import java.time.LocalDate; import java.util.stream.Collectors; @LiteflowComponent("update_stock") -public class UpdateStockNode extends NodeComponent { +public class UpdateStock extends NodeComponent { private final StockRepository stockRepository; private final TuShareService tuShareService; - public UpdateStockNode(StockRepository stockRepository, TuShareService tuShareService) { + public UpdateStock(StockRepository stockRepository, TuShareService tuShareService) { this.stockRepository = stockRepository; this.tuShareService = tuShareService; } diff --git a/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateYearly.java b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateYearly.java new file mode 100644 index 0000000..9f46f3c --- /dev/null +++ b/leopard-server/src/main/java/com/lanyuanxiaoyao/leopard/server/service/task/UpdateYearly.java @@ -0,0 +1,70 @@ +package com.lanyuanxiaoyao.leopard.server.service.task; + +import com.lanyuanxiaoyao.leopard.core.entity.Daily; +import com.lanyuanxiaoyao.leopard.core.entity.QYearly; +import com.lanyuanxiaoyao.leopard.core.entity.Yearly; +import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository; +import com.lanyuanxiaoyao.leopard.core.repository.StockRepository; +import com.lanyuanxiaoyao.leopard.core.repository.YearlyRepository; +import com.lanyuanxiaoyao.leopard.server.service.TaskService; +import com.yomahub.liteflow.annotation.LiteflowComponent; +import lombok.extern.slf4j.Slf4j; +import org.springframework.transaction.support.TransactionTemplate; + +@Slf4j +@LiteflowComponent("update_yearly") +public class UpdateYearly extends TaskNodeComponent { + private final StockRepository stockRepository; + private final DailyRepository dailyRepository; + private final YearlyRepository yearlyRepository; + + private final TransactionTemplate transactionTemplate; + + protected UpdateYearly(TaskService taskService, StockRepository stockRepository, DailyRepository dailyRepository, YearlyRepository yearlyRepository, TransactionTemplate transactionTemplate) { + super(taskService); + this.stockRepository = stockRepository; + this.dailyRepository = dailyRepository; + this.yearlyRepository = yearlyRepository; + this.transactionTemplate = transactionTemplate; + } + + @Override + public void process() { + var startYear = dailyRepository.findMinTradeDate().getYear(); + var endYear = dailyRepository.findMaxTradeDate().getYear(); + var stocks = stockRepository.findAll(); + for (var year = startYear; year <= endYear; year++) { + var currentYear = year; + transactionTemplate.execute(status -> { + try { + for (var stock : stocks) { + if (stock.getListedDate().getYear() > currentYear) { + continue; + } + var dailies = dailyRepository.findAllByTradeDate_YearAndStock_Code(currentYear, stock.getCode()); + var yearly = yearlyRepository.findOne( + QYearly.yearly.stock.code.eq(stock.getCode()) + .and(QYearly.yearly.year.eq(currentYear)) + ).orElseGet(Yearly::new); + yearly.setStock(stock); + yearly.setYear(currentYear); + yearly.setClose(dailies.getLast().getHfqClose()); + yearly.setOpen(dailies.getFirst().getHfqOpen()); + yearly.setHigh(dailies.stream().map(Daily::getHfqHigh).max(Double::compareTo).orElse(0.0)); + yearly.setLow(dailies.stream().map(Daily::getHfqLow).min(Double::compareTo).orElse(0.0)); + yearly.setVolume(dailies.stream().mapToDouble(Daily::getVolume).sum()); + yearly.setTurnover(dailies.stream().mapToDouble(Daily::getTurnover).sum()); + yearly.setPriceChangeAmount(yearly.getClose() - yearly.getOpen()); + yearly.setPriceFluctuationRange((yearly.getClose() - yearly.getOpen()) / yearly.getOpen()); + yearlyRepository.save(yearly); + } + return true; + } catch (Exception exception) { + log.error("Error", exception); + status.setRollbackOnly(); + return false; + } + }); + } + } +}