From f4fef2bd95533026d2cc08fcdd49757ea94fd13e Mon Sep 17 00:00:00 2001 From: lanyuanxiaoyao Date: Fri, 31 Oct 2025 00:56:06 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=B0=9D=E8=AF=95=E5=A4=9A=E5=9B=BE?= =?UTF-8?q?=E7=94=9F=E6=88=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../leopard/strategy/StrategyApplication.java | 55 +++++++++++++------ .../src/main/resources/templates/report.html | 48 +++++++++++++++- 2 files changed, 85 insertions(+), 18 deletions(-) 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 6074d89..4037233 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 @@ -4,8 +4,11 @@ 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.Daily; import com.lanyuanxiaoyao.leopard.core.entity.QDaily; +import com.lanyuanxiaoyao.leopard.core.helper.TaHelper; import com.lanyuanxiaoyao.leopard.core.repository.DailyRepository; +import com.lanyuanxiaoyao.leopard.core.repository.StockCollectionRepository; import jakarta.annotation.Resource; import java.io.IOException; import java.nio.file.Files; @@ -13,7 +16,6 @@ import java.nio.file.Path; import java.time.LocalDate; import java.util.ArrayList; import java.util.List; -import java.util.Map; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @@ -30,6 +32,8 @@ public class StrategyApplication { @Resource private DailyRepository dailyRepository; + @Resource + private StockCollectionRepository stockCollectionRepository; public static void main(String[] args) { SpringApplication.run(StrategyApplication.class, args); @@ -38,26 +42,43 @@ public class StrategyApplication { @Transactional(readOnly = true) @EventListener(ApplicationReadyEvent.class) 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() - ); + var charts = Dict.create(); + List.of("000048.SZ", "000333.SZ", "000568.SZ", "000596.SZ", "000651.SZ", "000848.SZ", "000858.SZ", "000933.SZ", "002027.SZ", "002032.SZ", "002142.SZ", "002192.SZ", "002415.SZ", "002432.SZ", "002475.SZ", "002517.SZ", "002555.SZ", "002648.SZ", "002756.SZ", "002847.SZ", "600036.SH", "600096.SH", "600132.SH", "600188.SH", "600309.SH", "600426.SH", "600436.SH", "600519.SH", "600546.SH", "600563.SH", "600702.SH", "600779.SH", "600803.SH", "600809.SH", "600961.SH", "601001.SH", "601100.SH", "601138.SH", "601225.SH", "601899.SH", "601919.SH", "603195.SH", "603198.SH", "603288.SH", "603369.SH", "603444.SH", "603565.SH", "603568.SH", "603605.SH", "603688.SH") + .parallelStream() + .forEach(code -> { + var dailies = dailyRepository.findAll( + QDaily.daily.stock.code.eq(code) + .and(QDaily.daily.tradeDate.after(LocalDate.of(2025, 1, 1))), + QDaily.daily.tradeDate.asc() + ); - 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 sma30 = TaHelper.sma(dailies, 30, Daily::getHfqClose); + var slopes = new ArrayList(); + slopes.add(0.0); + for (int i = 1; i < sma30.size(); i++) { + slopes.add(((sma30.get(i) - sma30.get(i - 1)) * 1000.0) / sma30.get(i - 1)); + } + + 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())); + } + + charts.set( + code, + Dict.create() + .set("xList", xList) + .set("yList", yList) + .set("sma30", sma30) + .set("sma30Slopes", slopes) + ); + }); 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)) - ) + Dict.create().set("charts", charts) )); } } diff --git a/leopard-strategy/src/main/resources/templates/report.html b/leopard-strategy/src/main/resources/templates/report.html index d4ac33b..e8f560f 100644 --- a/leopard-strategy/src/main/resources/templates/report.html +++ b/leopard-strategy/src/main/resources/templates/report.html @@ -29,7 +29,7 @@ body: { className: 'mt-2', type: 'chart', - height: 500, + height: 800, config: { title: { text: title, @@ -103,6 +103,32 @@ }, yAxis: [ { + position: 'left', + scale: true, + axisLine: { + lineStyle: { + color: '#e0e0e0', + }, + }, + axisLabel: { + color: '#666', + fontWeight: 'bold', + formatter: function (value) { + return value.toFixed(2) + }, + }, + splitLine: { + lineStyle: { + type: 'dashed', + color: '#f0f0f0', + }, + }, + axisTick: { + show: false, + }, + }, + { + position: 'right', scale: true, axisLine: { lineStyle: { @@ -169,6 +195,26 @@ borderWidth: 1, }, }, + { + type: 'line', + yAxisIndex: 0, + data: '${sma30 || []}', + smooth: true, + symbol: 'none', + lineStyle: { + color: 'rgba(0,111,255,0.5)', + }, + }, + { + type: 'line', + yAxisIndex: 1, + data: '${sma30Slopes || []}', + smooth: true, + symbol: 'none', + lineStyle: { + color: 'rgba(0,255,81,0.5)', + }, + }, ], }, },