Compare commits
2 Commits
8c4e3baacb
...
452d1c681d
| Author | SHA1 | Date | |
|---|---|---|---|
| 452d1c681d | |||
| 42b402d4ef |
@@ -41,7 +41,7 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
this.dailyRepository = dailyRepository;
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findFinanceIndicator", cacheManager = "long-cache", sync = true)
|
||||
public Optional<FinanceIndicator> findFinanceIndicator(Long stockId, Integer year) {
|
||||
return financeIndicatorRepository.findOne(
|
||||
QFinanceIndicator.financeIndicator.year.eq(year)
|
||||
@@ -49,7 +49,7 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
);
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findFinanceIndicatorRecent", cacheManager = "long-cache", sync = true)
|
||||
public List<FinanceIndicator> findFinanceIndicatorRecent(Long stockId, int years) {
|
||||
var current = LocalDate.now();
|
||||
return financeIndicatorRepository.findAll(
|
||||
@@ -59,7 +59,7 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
);
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findDailyRecent", cacheManager = "long-cache", sync = true)
|
||||
public List<Daily> findDailyRecent(Long stockId, int days) {
|
||||
var current = LocalDate.now();
|
||||
return dailyRepository.findAll(
|
||||
@@ -69,12 +69,12 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
);
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findDailyLatest", cacheManager = "long-cache", sync = true)
|
||||
public Optional<Daily> findDailyLatest(Long stockId) {
|
||||
return dailyRepository.findLatest(stockId);
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findYearlyRecent", cacheManager = "long-cache", sync = true)
|
||||
public List<Yearly> findYearlyRecent(Long stockId, int years) {
|
||||
var current = LocalDate.now().withMonth(1).withDayOfMonth(1);
|
||||
var start = current.minusYears(years).getYear();
|
||||
@@ -112,7 +112,7 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findMonthlyRecent", cacheManager = "long-cache", sync = true)
|
||||
public List<Monthly> findMonthlyRecent(Long stockId, int months) {
|
||||
var end = LocalDate.now().withDayOfMonth(1);
|
||||
var start = end.minusMonths(months);
|
||||
@@ -162,7 +162,7 @@ public class StockService extends SimpleServiceSupport<Stock> {
|
||||
.toList();
|
||||
}
|
||||
|
||||
@Cacheable(value = "long-cache", sync = true)
|
||||
@Cacheable(value = "findWeeklyRecent", cacheManager = "long-cache", sync = true)
|
||||
public List<Weekly> findWeeklyRecent(Long stockId, int weeks) {
|
||||
var end = LocalDate.now().with(ChronoField.DAY_OF_WEEK, 1);
|
||||
var start = end.minusWeeks(weeks);
|
||||
|
||||
@@ -135,6 +135,36 @@ public class StockController extends SimpleControllerSupport<Stock, Void, StockD
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@GetMapping("weekly/{id}")
|
||||
public GlobalResponse<Map<String, Object>> weeklyCharts(@PathVariable("id") Long id) {
|
||||
var data = stockService.findWeeklyRecent(id, 50);
|
||||
var xList = new ArrayList<String>();
|
||||
var yList = new ArrayList<List<Double>>();
|
||||
for (var weekly : data) {
|
||||
xList.add(weekly.tradeDate().toString());
|
||||
yList.add(List.of(weekly.open(), weekly.close(), weekly.low(), weekly.high()));
|
||||
}
|
||||
return GlobalResponse.responseMapData(Map.of(
|
||||
"xList", xList, "yList", yList
|
||||
));
|
||||
}
|
||||
|
||||
@SuppressWarnings("DuplicatedCode")
|
||||
@GetMapping("monthly/{id}")
|
||||
public GlobalResponse<Map<String, Object>> monthlyCharts(@PathVariable("id") Long id) {
|
||||
var data = stockService.findMonthlyRecent(id, 24);
|
||||
var xList = new ArrayList<String>();
|
||||
var yList = new ArrayList<List<Double>>();
|
||||
for (var monthly : data) {
|
||||
xList.add(monthly.tradeDate().toString());
|
||||
yList.add(List.of(monthly.open(), monthly.close(), monthly.low(), monthly.high()));
|
||||
}
|
||||
return GlobalResponse.responseMapData(Map.of(
|
||||
"xList", xList, "yList", yList
|
||||
));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Function<Void, Stock> saveItemMapper() {
|
||||
throw new UnsupportedOperationException();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {AlertComponent, attachmentAdpator, makeTranslator, render, type Schema, ToastComponent} from 'amis'
|
||||
import {AlertComponent, type Api, attachmentAdpator, makeTranslator, render, type Schema, ToastComponent} from 'amis'
|
||||
import 'amis/lib/themes/antd.css'
|
||||
import 'amis/lib/helper.css'
|
||||
import 'amis/sdk/iconfont.css'
|
||||
@@ -561,6 +561,139 @@ const financePropertyLabel = (idField: string, label: string, type: FinanceType,
|
||||
}
|
||||
}
|
||||
|
||||
const candleChart = (title: string, subtitle: string, api: Api): Schema => {
|
||||
return {
|
||||
type: 'chart',
|
||||
height: 500,
|
||||
api: api,
|
||||
config: {
|
||||
title: {
|
||||
text: title,
|
||||
subtext: subtitle,
|
||||
},
|
||||
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,
|
||||
formatter: function (params: any) {
|
||||
const param = params[0]
|
||||
const open = toNumber(param.data[1]).toFixed(2)
|
||||
const close = toNumber(param.data[2]).toFixed(2)
|
||||
const lowest = toNumber(param.data[3]).toFixed(2)
|
||||
const highest = toNumber(param.data[4]).toFixed(2)
|
||||
|
||||
return `<div class="text-center font-bold mb-2">${param.name}</div>
|
||||
<div class="text-center">
|
||||
<span>开盘:</span>
|
||||
<span class="font-bold ml-4">${open}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>收盘:</span>
|
||||
<span class="font-bold ml-4">${close}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>最低:</span>
|
||||
<span class="font-bold ml-4">${lowest}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>最高:</span>
|
||||
<span class="font-bold ml-4">${highest}</span>
|
||||
</div>`
|
||||
},
|
||||
},
|
||||
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: {
|
||||
scale: true,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e0e0e0',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontWeight: 'bold',
|
||||
formatter: function (value: number) {
|
||||
return value.toFixed(2)
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#f0f0f0',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
{
|
||||
show: true,
|
||||
type: 'slider',
|
||||
top: '90%',
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'candlestick',
|
||||
data: '${yList || []}',
|
||||
itemStyle: {
|
||||
color: '#eb5454',
|
||||
color0: '#4aaa93',
|
||||
borderColor: '#eb5454',
|
||||
borderColor0: '#4aaa93',
|
||||
borderWidth: 1,
|
||||
},
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
export function stockListColumns(idField: string = 'id', extraColumns: Array<ColumnSchema> = []) {
|
||||
return [
|
||||
{
|
||||
@@ -803,137 +936,21 @@ export function stockListColumns(idField: string = 'id', extraColumns: Array<Col
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'chart',
|
||||
title: '100日线数据',
|
||||
height: 500,
|
||||
api: `get:${commonInfo.baseUrl}/stock/daily/\${${idField}}`,
|
||||
config: {
|
||||
title: {
|
||||
text: '100日线数据',
|
||||
subtext: '后复权数据',
|
||||
},
|
||||
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,
|
||||
formatter: function (params: any) {
|
||||
const param = params[0]
|
||||
const open = toNumber(param.data[1]).toFixed(2)
|
||||
const close = toNumber(param.data[2]).toFixed(2)
|
||||
const lowest = toNumber(param.data[3]).toFixed(2)
|
||||
const highest = toNumber(param.data[4]).toFixed(2)
|
||||
|
||||
return `<div class="text-center font-bold mb-2">${param.name}</div>
|
||||
<div class="text-center">
|
||||
<span>开盘:</span>
|
||||
<span class="font-bold ml-4">${open}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>收盘:</span>
|
||||
<span class="font-bold ml-4">${close}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>最低:</span>
|
||||
<span class="font-bold ml-4">${lowest}</span>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<span>最高:</span>
|
||||
<span class="font-bold ml-4">${highest}</span>
|
||||
</div>`
|
||||
},
|
||||
},
|
||||
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: {
|
||||
scale: true,
|
||||
axisLine: {
|
||||
lineStyle: {
|
||||
color: '#e0e0e0',
|
||||
},
|
||||
},
|
||||
axisLabel: {
|
||||
color: '#666',
|
||||
fontWeight: 'bold',
|
||||
formatter: function (value: number) {
|
||||
return value.toFixed(2)
|
||||
},
|
||||
},
|
||||
splitLine: {
|
||||
lineStyle: {
|
||||
type: 'dashed',
|
||||
color: '#f0f0f0',
|
||||
},
|
||||
},
|
||||
axisTick: {
|
||||
show: false,
|
||||
},
|
||||
},
|
||||
dataZoom: [
|
||||
{
|
||||
type: 'inside',
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
{
|
||||
show: true,
|
||||
type: 'slider',
|
||||
top: '90%',
|
||||
start: 0,
|
||||
end: 100,
|
||||
},
|
||||
],
|
||||
series: [
|
||||
{
|
||||
type: 'candlestick',
|
||||
data: '${yList || []}',
|
||||
itemStyle: {
|
||||
color: '#eb5454',
|
||||
color0: '#4aaa93',
|
||||
borderColor: '#eb5454',
|
||||
borderColor0: '#4aaa93',
|
||||
borderWidth: 1,
|
||||
},
|
||||
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
candleChart(
|
||||
'100日线数据',
|
||||
'后复权数据',
|
||||
`get:${commonInfo.baseUrl}/stock/daily/\${${idField}}`,
|
||||
),
|
||||
candleChart(
|
||||
'50周线数据',
|
||||
'后复权数据',
|
||||
`get:${commonInfo.baseUrl}/stock/weekly/\${${idField}}`,
|
||||
),
|
||||
candleChart(
|
||||
'24月线数据',
|
||||
'后复权数据',
|
||||
`get:${commonInfo.baseUrl}/stock/monthly/\${${idField}}`,
|
||||
),
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user