diff --git a/leopard-strategy/pom.xml b/leopard-strategy/pom.xml
index dcb4bdd..f36d688 100644
--- a/leopard-strategy/pom.xml
+++ b/leopard-strategy/pom.xml
@@ -34,6 +34,15 @@
commonmark-ext-gfm-tables
0.26.0
+
+ org.thymeleaf
+ thymeleaf
+
+
+
+ cn.hutool
+ hutool-extra
+
org.springframework.boot
diff --git a/leopard-strategy/src/main/java/com/lanyuanxiaoyao/leopard/strategy/StrategyApplication.java b/leopard-strategy/src/main/java/com/lanyuanxiaoyao/leopard/strategy/StrategyApplication.java
index e88df2a..6074d89 100644
--- a/leopard-strategy/src/main/java/com/lanyuanxiaoyao/leopard/strategy/StrategyApplication.java
+++ b/leopard-strategy/src/main/java/com/lanyuanxiaoyao/leopard/strategy/StrategyApplication.java
@@ -1,23 +1,17 @@
package com.lanyuanxiaoyao.leopard.strategy;
-import cn.hutool.core.util.ObjectUtil;
-import cn.hutool.core.util.StrUtil;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.lanyuanxiaoyao.leopard.core.entity.Daily;
-import com.lanyuanxiaoyao.leopard.core.entity.QStock;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.extra.template.TemplateConfig;
+import cn.hutool.extra.template.TemplateEngine;
+import cn.hutool.extra.template.TemplateUtil;
+import com.lanyuanxiaoyao.leopard.core.entity.QDaily;
import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository;
-import com.lanyuanxiaoyao.leopard.core.repository.StockRepository;
-import com.lanyuanxiaoyao.leopard.core.service.AssessmentService;
-import com.lanyuanxiaoyao.leopard.core.service.StockService;
-import com.lanyuanxiaoyao.leopard.core.service.TuShareService;
-import com.lanyuanxiaoyao.leopard.core.service.selector.PyramidStockSelector;
-import com.lanyuanxiaoyao.leopard.core.strategy.TradeEngine;
import jakarta.annotation.Resource;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.LocalDate;
-import java.util.Comparator;
+import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
@@ -32,296 +26,38 @@ import org.springframework.transaction.annotation.Transactional;
@SpringBootApplication(scanBasePackages = "com.lanyuanxiaoyao.leopard")
@EnableJpaAuditing
public class StrategyApplication {
- private static final ObjectMapper mapper = new ObjectMapper();
- @Resource
- private PyramidStockSelector pyramidStockSelector;
- @Resource
- private AssessmentService assessmentService;
- @Resource
- private TuShareService tuShareService;
+ private static final TemplateEngine engine = TemplateUtil.createEngine(new TemplateConfig("templates", TemplateConfig.ResourceMode.CLASSPATH));
+
@Resource
private DailyRepository dailyRepository;
- @Resource
- private StockRepository stockRepository;
- @Resource
- private StockService stockService;
- @Resource
- private TradeEngine tradeEngine;
public static void main(String[] args) {
SpringApplication.run(StrategyApplication.class, args);
}
- private static void render(Map data) throws IOException {
- Files.writeString(
- Path.of("result.html"),
- StrUtil.format(
- // language=HTML
- """
-
-
-
-
-
- Strategy
-
-
-
-
-
-
-
-
-
-
-
- """,
- mapper.writeValueAsString(data)
- )
- );
- }
-
@Transactional(readOnly = true)
@EventListener(ApplicationReadyEvent.class)
- public void test() {
- var stock = stockRepository.findOne(QStock.stock.code.eq("000001.SZ")).orElseThrow();
- var asset = tradeEngine.backtest(
- List.of(stock.getId()),
- (now, currentAsset, dailies) -> {
- return dailies.entrySet()
- .stream()
- .map(entry -> {
- var stockId = entry.getKey();
- var stockDailies = entry.getValue()
- .stream()
- .sorted(Comparator.comparing(Daily::getTradeDate))
- .toList();
- var yesterday = stockDailies.getLast();
- if (yesterday.getHfqClose() > yesterday.getHfqOpen()) {
- log.info("{} Buy for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose());
- return new TradeEngine.Trade(now, stockId, 100);
- } else if (yesterday.getHfqClose() < yesterday.getHfqOpen()) {
- var hold = currentAsset.getStocks().getOrDefault(stockId, 0);
- if (hold > 0) {
- log.info("{} Sell for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose());
- return new TradeEngine.Trade(now, stockId, -1 * hold);
- }
- } else {
- log.info("{} Hold for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose());
- }
- return null;
- })
- .filter(ObjectUtil::isNotNull)
- .toList();
- },
- LocalDate.of(2024, 12, 1),
- LocalDate.of(2024, 12, 31)
+ public void test() throws IOException {
+ var dailies = dailyRepository.findAll(
+ QDaily.daily.stock.code.eq("000001.SZ")
+ .and(QDaily.daily.tradeDate.after(LocalDate.of(2025, 1, 1))),
+ QDaily.daily.tradeDate.asc()
);
- log.info("Final Cash: {}", asset.getCash());
- for (var history : asset.getHistories()) {
- log.info("Date: {} Cash: {} Trade: {}", history.date(), history.cash(), history.trades().values());
+
+ var xList = new ArrayList();
+ var yList = new ArrayList>();
+ for (var daily : dailies) {
+ xList.add(daily.getTradeDate().toString());
+ yList.add(List.of(daily.getHfqOpen(), daily.getHfqClose(), daily.getHfqLow(), daily.getHfqHigh()));
}
+
+ var template = engine.getTemplate("report.html");
+ Files.writeString(Path.of("report.html"), template.render(
+ Dict.create().set(
+ "charts",
+ Dict.create()
+ .set("日线数据", Map.of("xList", xList, "yList", yList))
+ )
+ ));
}
}
diff --git a/leopard-strategy/src/main/resources/templates/report.html b/leopard-strategy/src/main/resources/templates/report.html
new file mode 100644
index 0000000..d4ac33b
--- /dev/null
+++ b/leopard-strategy/src/main/resources/templates/report.html
@@ -0,0 +1,191 @@
+
+
+
+
+
+ Strategy
+
+
+
+
+
+
+
+
+
+
+
diff --git a/pom.xml b/pom.xml
index c5dc008..c08ecdf 100644
--- a/pom.xml
+++ b/pom.xml
@@ -63,6 +63,11 @@
hutool-http
${hutool.version}
+
+ cn.hutool
+ hutool-extra
+ ${hutool.version}
+
com.yomahub