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