1
0

Compare commits

...

3 Commits

26 changed files with 101 additions and 91 deletions

View File

@@ -20,10 +20,18 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>io.github.ralfkonrad.quantlib_for_maven</groupId>

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.helper;
package com.lanyuanxiaoyao.leopard.core.helper;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;

View File

@@ -32,11 +32,7 @@ public class AssessmentService {
public Set<Result> assess(Set<Stock> stocks, int year) {
if (ObjectUtil.isNotEmpty(stocks)) {
var industries = stocks
.stream()
.map(Stock::getIndustry)
.collect(Collectors.toSet());
var topChange = industryService.topChange(year, industries, stocks);
var topChange = industryService.topChange(year, stocks);
var dailyMap = dailyRepository.findAll(
QDaily.daily.tradeDate.year().eq(year)
.and(QDaily.daily.stock.in(stocks))

View File

@@ -1,5 +1,6 @@
package com.lanyuanxiaoyao.leopard.core.service;
import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.QDaily;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
@@ -31,29 +32,24 @@ public class IndustryService {
}
public Map<IndustryYearlyKey, Double> topChange(int year) {
return topChange(year, null, null);
return topChange(year, null);
}
public Map<IndustryYearlyKey, Double> topChange(int year, Set<String> includeIndustries) {
return topChange(year, includeIndustries, null);
}
public Map<IndustryYearlyKey, Double> topChange(int year, Set<String> includeIndustries, Set<Stock> includeStocks) {
return topChange(year, year, includeIndustries, includeStocks);
public Map<IndustryYearlyKey, Double> topChange(int year, Set<Stock> includeStocks) {
return topChange(year, year, includeStocks);
}
public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear) {
return topChange(startYear, endYear, null, null);
return topChange(startYear, endYear, null);
}
public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear, Set<String> includeIndustries) {
return topChange(startYear, endYear, includeIndustries, null);
}
public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear, Set<String> includeIndustries, Set<Stock> includeStocks) {
public Map<IndustryYearlyKey, Double> topChange(int startYear, int endYear, Set<Stock> includeStocks) {
var includeIndustries = ObjectUtil.isNull(includeStocks)
? null
: includeStocks.stream().map(Stock::getIndustry).collect(Collectors.toSet());
return stockRepository.findDistinctIndustries()
.parallelStream()
.filter(industry -> includeIndustries == null || includeIndustries.contains(industry))
.filter(o -> ObjectUtil.isNull(includeIndustries) || includeIndustries.contains(o))
.flatMap(industry -> {
var keys = new ArrayList<IndustryYearlyKey>();
for (int year = startYear; year <= endYear; year++) {
@@ -62,7 +58,6 @@ public class IndustryService {
return keys.stream();
})
.map(key -> {
log.info("计算行业 {} {} 年度涨跌幅", key.industry(), key.year());
var maxChange = dailyRepository
.findAll(
QDaily.daily.stock.industry.eq(key.industry())
@@ -90,4 +85,14 @@ public class IndustryService {
public record IndustryYearlyKey(String industry, int year) {
}
public record IndustryYearlyData(
String industry,
int year,
double maxChange,
double minChange,
double avgChange,
double medianChange
) {
}
}

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service;
package com.lanyuanxiaoyao.leopard.core.service;
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
import com.lanyuanxiaoyao.leopard.core.repository.StockCollectionRepository;

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service;
package com.lanyuanxiaoyao.leopard.core.service;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.Daily_;

View File

@@ -1,17 +1,16 @@
package com.lanyuanxiaoyao.leopard.server.service;
package com.lanyuanxiaoyao.leopard.core.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.core.repository.TaskRepository;
import com.lanyuanxiaoyao.leopard.server.service.task.PyramidSelect;
import com.lanyuanxiaoyao.leopard.server.service.task.TaskRunner;
import com.lanyuanxiaoyao.leopard.server.service.task.UpdateDailyTask;
import com.lanyuanxiaoyao.leopard.server.service.task.UpdateFinanceIndicatorTask;
import com.lanyuanxiaoyao.leopard.server.service.task.UpdateStockTask;
import com.lanyuanxiaoyao.leopard.server.service.task.UpdateYearlyTask;
import com.lanyuanxiaoyao.leopard.core.task.PyramidSelect;
import com.lanyuanxiaoyao.leopard.core.task.TaskRunner;
import com.lanyuanxiaoyao.leopard.core.task.UpdateDailyTask;
import com.lanyuanxiaoyao.leopard.core.task.UpdateFinanceIndicatorTask;
import com.lanyuanxiaoyao.leopard.core.task.UpdateStockTask;
import com.lanyuanxiaoyao.leopard.core.task.UpdateYearlyTask;
import com.lanyuanxiaoyao.service.template.service.SimpleServiceSupport;
import jakarta.transaction.Transactional;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
@@ -20,9 +19,7 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;
/**
@@ -33,7 +30,6 @@ import org.springframework.stereotype.Service;
@Service
public class TaskService extends SimpleServiceSupport<Task> {
private final ExecutorService executor = Executors.newFixedThreadPool(50);
private final TaskRepository taskRepository;
private final ApplicationContext context;
@Getter
@@ -49,17 +45,9 @@ public class TaskService extends SimpleServiceSupport<Task> {
public TaskService(TaskRepository repository, ApplicationContext context) {
super(repository);
this.taskRepository = repository;
this.context = context;
}
@Transactional(rollbackOn = Throwable.class)
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady() {
log.warn("更新所有未完成的任务状态为失败");
taskRepository.updateAllRunningTaskToFailure();
}
public TaskTemplate getTemplate(String templateId) {
return templateMap.get(templateId);
}

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service;
package com.lanyuanxiaoyao.leopard.core.service;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;

View File

@@ -35,7 +35,6 @@ public class PyramidStockSelector implements StockSelector<PyramidStockSelector.
// 选择至少有最近5年财报的股票
// 有点奇怪001400.SZ有近5年的财报但资料显示是2025年才上市的
var stocks = stockRepository.findAll(QStock.stock.listedDate.before(LocalDate.of(request.year(), 1, 1)));
log.info("Year: {} Stock: {}", request.year(), stocks.size());
var scores = stocks.stream().collect(Collectors.toMap(stock -> stock, code -> 0));
for (Stock stock : stocks) {
var recentIndicators = stock.getIndicators()

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
import com.lanyuanxiaoyao.leopard.core.repository.StockCollectionRepository;
@@ -35,11 +35,19 @@ public class PyramidSelect extends TaskRunner {
@Override
public String process(Map<String, Object> params, StepUpdater updater) throws Exception {
var candidates = pyramidStockSelector.select(new PyramidStockSelector.Request(LocalDate.now().getYear(), 50));
var collection = new StockCollection();
collection.setName("金字塔选股");
collection.setDescription("金字塔选股");
collection.setStocks(candidates.stream().map(StockSelector.Candidate::stock).collect(Collectors.toSet()));
stockCollectionRepository.save(collection);
return null;
return """
| Code | Name | Score |
| ---- | ---- | ----- |
%s
""".formatted(candidates.stream()
.map(candidate -> "| %s | %s | %.2f |".formatted(candidate.stock().getCode(), candidate.stock().getName(), candidate.score()))
.collect(Collectors.joining("\n")));
}
}

View File

@@ -1,11 +1,11 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.core.repository.TaskRepository;
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import java.time.LocalDateTime;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;

View File

@@ -1,14 +1,14 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.lanyuanxiaoyao.leopard.core.service.TuShareService;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashMap;

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
@@ -6,10 +6,10 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import com.lanyuanxiaoyao.leopard.core.entity.FinanceIndicator;
import com.lanyuanxiaoyao.leopard.core.entity.QFinanceIndicator;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.core.repository.FinanceIndicatorRepository;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.lanyuanxiaoyao.leopard.core.service.TuShareService;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;

View File

@@ -1,9 +1,9 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import cn.hutool.core.util.EnumUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.server.service.TuShareService;
import com.lanyuanxiaoyao.leopard.core.service.TuShareService;
import java.time.LocalDate;
import java.util.Map;
import java.util.stream.Collectors;

View File

@@ -1,4 +1,4 @@
package com.lanyuanxiaoyao.leopard.server.service.task;
package com.lanyuanxiaoyao.leopard.core.task;
import com.lanyuanxiaoyao.leopard.core.entity.Daily;
import com.lanyuanxiaoyao.leopard.core.entity.QDaily;

View File

@@ -41,24 +41,6 @@
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-core</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-http</artifactId>
</dependency>
<dependency>
<groupId>io.github.ralfkonrad.quantlib_for_maven</groupId>
<artifactId>quantlib</artifactId>
</dependency>
<dependency>
<groupId>org.ta4j</groupId>
<artifactId>ta4j-core</artifactId>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>

View File

@@ -1,5 +1,7 @@
package com.lanyuanxiaoyao.leopard.server;
import com.lanyuanxiaoyao.leopard.core.repository.TaskRepository;
import jakarta.transaction.Transactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
@@ -15,11 +17,20 @@ import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
@SpringBootApplication(scanBasePackages = "com.lanyuanxiaoyao.leopard")
@EnableJpaAuditing
public class LeopardServerApplication implements ApplicationRunner {
private final TaskRepository taskRepository;
public LeopardServerApplication(TaskRepository taskRepository) {
this.taskRepository = taskRepository;
}
public static void main(String[] args) {
SpringApplication.run(LeopardServerApplication.class, args);
}
@Transactional(rollbackOn = Throwable.class)
@Override
public void run(ApplicationArguments args) {
log.warn("更新所有未完成的任务状态为失败");
taskRepository.updateAllRunningTaskToFailure();
}
}

View File

@@ -3,7 +3,7 @@ package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import java.util.Arrays;
import java.util.Comparator;

View File

@@ -1,7 +1,7 @@
package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import com.lanyuanxiaoyao.leopard.server.service.QuartzService;
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import java.time.LocalDateTime;
import java.util.List;

View File

@@ -1,9 +1,9 @@
package com.lanyuanxiaoyao.leopard.server.controller;
import com.lanyuanxiaoyao.leopard.core.entity.StockCollection;
import com.lanyuanxiaoyao.leopard.core.service.StockCollectionService;
import com.lanyuanxiaoyao.leopard.core.service.StockService;
import com.lanyuanxiaoyao.leopard.server.entity.StockDetailVo;
import com.lanyuanxiaoyao.leopard.server.service.StockCollectionService;
import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.util.HashSet;
import java.util.Set;

View File

@@ -2,9 +2,9 @@ package com.lanyuanxiaoyao.leopard.server.controller;
import cn.hutool.core.bean.BeanUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Stock;
import com.lanyuanxiaoyao.leopard.core.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.core.service.StockService;
import com.lanyuanxiaoyao.leopard.server.entity.StockDetailVo;
import com.lanyuanxiaoyao.leopard.server.helper.NumberHelper;
import com.lanyuanxiaoyao.leopard.server.service.StockService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.time.LocalDate;

View File

@@ -4,7 +4,7 @@ import cn.hutool.core.date.BetweenFormatter;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.lanyuanxiaoyao.leopard.core.entity.Task;
import com.lanyuanxiaoyao.leopard.server.service.TaskService;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import com.lanyuanxiaoyao.service.template.controller.GlobalResponse;
import com.lanyuanxiaoyao.service.template.controller.SimpleControllerSupport;
import java.time.Duration;

View File

@@ -3,6 +3,7 @@ package com.lanyuanxiaoyao.leopard.server.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.leopard.core.service.TaskService;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;

View File

@@ -0,0 +1,14 @@
spring:
datasource:
url: jdbc:h2:file:./leopard;DB_CLOSE_ON_EXIT=TRUE
username: leopard
password: leopard
driver-class-name: org.h2.Driver
quartz:
jdbc:
platform: h2
properties:
org:
quartz:
jobStore:
driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate

View File

@@ -24,14 +24,6 @@
<groupId>com.yomahub</groupId>
<artifactId>liteflow-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>io.github.ralfkonrad.quantlib_for_maven</groupId>
<artifactId>quantlib</artifactId>
</dependency>
<dependency>
<groupId>org.ta4j</groupId>
<artifactId>ta4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.commonmark</groupId>
<artifactId>commonmark</artifactId>
@@ -53,6 +45,11 @@
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>

View File

@@ -56,9 +56,10 @@ function TaskDetail() {
},
{
visibleOn: 'result',
type: 'editor',
type: 'markdown-enhance',
name: 'result',
label: '结果',
content: '${result}',
},
],
},