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 d9a44e1..efdf1a0 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 @@ -78,16 +78,12 @@ public class StrategyApplication { .toList(); var yesterday = stockDailies.getLast(); if (yesterday.getHfqClose() > yesterday.getHfqOpen()) { - log.info("{} Buy for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose()); return 100; } else if (yesterday.getHfqClose() < yesterday.getHfqOpen()) { var hold = currentAsset.getVolume(); if (hold > 0) { - log.info("{} Sell for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose()); return -1 * hold; } - } else { - log.info("{} Hold for price {} {}", now, yesterday.getHfqOpen(), yesterday.getHfqClose()); } return 0; }, @@ -122,24 +118,28 @@ public class StrategyApplication { .set( "日线", Dict.create() + .set("type", "candle") .set("xList", dailyXList) .set("yList", dailyYList) .set( "points", asset.getTrades() .stream() - .map(trade -> { - return Dict.create() - .set("value", trade.volume()) - .set("itemStyle", Dict.create() - .set("color", trade.volume() > 0 ? "#e5b8b5" : "#b5e2e5") - ) - .set("coord", List.of(trade.date().toString(), dailyCloseMapping.getOrDefault(trade.date().toString(), 0.0))); - } + .map(trade -> Dict.create() + .set("value", trade.volume()) + .set("itemStyle", Dict.create() + .set("color", trade.volume() > 0 ? "#e5b8b5" : "#b5e2e5") + ) + .set("coord", List.of(trade.date().toString(), dailyCloseMapping.getOrDefault(trade.date().toString(), 0.0))) ) .toList() ) ) + .set( + "资金", + Dict.create() + .set("type", "line") + ) ) ); /*log.info("Final Cash: {}", asset.getCash()); diff --git a/leopard-strategy/src/main/resources/templates/backtest_report.html b/leopard-strategy/src/main/resources/templates/backtest_report.html index ba360d1..eb736e9 100644 --- a/leopard-strategy/src/main/resources/templates/backtest_report.html +++ b/leopard-strategy/src/main/resources/templates/backtest_report.html @@ -234,6 +234,158 @@ } } + function lineChart(title, data) { + return { + type: 'service', + data: data, + body: { + className: 'mt-2', + type: 'chart', + height: 800, + config: { + title: { + text: title, + }, + backgroundColor: '#fff', + animation: true, + animationDuration: 1000, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'cross', + }, + backgroundColor: 'rgba(0, 0, 0, 0.7)', + borderColor: '#333', + borderWidth: 1, + textStyle: { + color: '#fff', + fontSize: 12, + }, + padding: 12, + }, + grid: { + left: '2%', + right: '2%', + top: '15%', + bottom: '15%', + containLabel: true, + }, + xAxis: { + data: '${xList || []}', + axisLine: { + lineStyle: { + color: '#e0e0e0', + }, + }, + axisLabel: { + color: '#666', + fontWeight: 'bold', + }, + splitLine: { + show: false, + }, + axisTick: { + show: false, + }, + }, + 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: { + color: '#e0e0e0', + }, + }, + axisLabel: { + color: '#666', + fontWeight: 'bold', + formatter: function (value) { + return value.toFixed(2) + }, + }, + splitLine: { + lineStyle: { + type: 'dashed', + color: '#f0f0f0', + }, + }, + axisTick: { + show: false, + }, + }, + { + scale: true, + axisLine: { + show: false, + }, + axisTick: { + show: false, + }, + axisLabel: { + show: false, + }, + splitLine: { + show: false, + }, + }, + ], + dataZoom: [ + { + type: 'inside', + start: 0, + end: 100, + }, + { + show: true, + type: 'slider', + top: '90%', + start: 0, + end: 100, + }, + ], + series: [ + { + type: 'line', + yAxisIndex: 0, + data: '${yList || []}', + smooth: true, + symbol: 'none', + lineStyle: { + color: 'rgba(0,111,255,0.5)', + }, + }, + ], + }, + }, + } + } + const data = /*[[${charts}]]*/ []; (function () { @@ -248,7 +400,19 @@ return { title: item?.title, body: Object.keys(item?.data ?? {}) - .map(key => candleChart(key, item.data[key])), + .map(key => { + let value = item.data[key] + let type = value['type'] + if (type) { + if (type === 'candle') + return candleChart(key, item.data[key]) + else if (type === 'line') + return lineChart(key, item.data[key]) + } else { + return null + } + }) + .filter(item => item), } }), },