本文我们来计算2023年沪深300行业涨跌幅,最后呈现的页面是这样的
先来说后端的代码,计算行业涨跌幅的原理就是将某个行业所有成分股的涨跌幅加起来,然后除以股票数量得到一个平均涨跌幅
// 查询行业涨跌幅
public List<CSI300IndustryRankVO> queryIndustryRank() {
// 首先将所有数据查出来
List<CSI300RankVO> csi300RankVOList = query2023rank(3, 300);
// 将沪深300所有成分股都查出来
List<CSI300Entity> csi300Entities = sqlIteCSI300Dao.queryAllItems();
// 记录涨跌幅
Map<String, Integer> numMap = new HashMap<>();
Map<String, Double> riseMap = new HashMap<>();
for (int i=0; i<csi300RankVOList.size(); i++) {
for (int j = 0; j < csi300Entities.size(); j++) {
if (csi300RankVOList.get(i).getName().equals(csi300Entities.get(j).getName())) {
if (!riseMap.containsKey(csi300Entities.get(j).getIndustry())) {
riseMap.put(csi300Entities.get(j).getIndustry(), csi300RankVOList.get(i).getRise());
numMap.put(csi300Entities.get(j).getIndustry(), 1);
} else {
Double rise = riseMap.get(csi300Entities.get(j).getIndustry()) + csi300RankVOList.get(i).getRise();
riseMap.put(csi300Entities.get(j).getIndustry(), rise);
Integer num = numMap.get(csi300Entities.get(j).getIndustry());
numMap.put(csi300Entities.get(j).getIndustry(), num + 1);
}
log.info("name:" + csi300RankVOList.get(i).getName() + " industry:" +
csi300Entities.get(j).getIndustry() + " rise:" +
csi300RankVOList.get(i).getRise());
break;
}
}
}
List<String> keyList = new ArrayList<>(riseMap.keySet());
List<CSI300IndustryRankVO> csi300IndustryRankVOList = new ArrayList<>();
for (int i=0; i<keyList.size(); i++) {
CSI300IndustryRankVO entity = new CSI300IndustryRankVO();
entity.setIndustry(keyList.get(i));
Double rise = riseMap.get(keyList.get(i));
rise = rise / numMap.get(keyList.get(i));
String str = String.format("%.2f", rise);
rise = Double.parseDouble(str);
log.info("行业:" + keyList.get(i) + " 数量: " + numMap.get(keyList.get(i)) + " 涨幅:" + rise);
entity.setRise(rise);
csi300IndustryRankVOList.add(entity);
}
// 按照涨幅降序排序
Collections.sort(csi300IndustryRankVOList, new Comparator<CSI300IndustryRankVO>() {
@Override
public int compare(CSI300IndustryRankVO o1, CSI300IndustryRankVO o2) {
if (o1.getRise() > o2.getRise()) {
return -1;
} else if (o1.getRise() == o2.getRise()) {
return 0;
} else {
return 1;
}
}
});
return csi300IndustryRankVOList;
}
// 将查询的数据缓存到内存中
private List<CSI300RankVO> cache = new ArrayList<>();
// 查询沪深300成分股2023年涨跌排行榜
public synchronized List<CSI300RankVO> query2023rank(int type, int limit) {
// 首先将所有的股票查出来
List<StockOptionVO> allCode = getAllCode();
List<CSI300RankVO> csi300RankVOList = new ArrayList<>();
if (cache.size() == 0) {
log.info("需要重新计算数据");
// 根据股票代码查询所有股票的涨跌幅
for (int i = 0; i < allCode.size(); i++) {
// 去除掉沪深300指数本身
if (allCode.get(i).getCode().equals("399300")) {
continue;
}
List<StockEntity> stockEntities = sqLiteStockDao.queryAllByCodeAndYear(allCode.get(i).getCode(), "2023");
CSI300RankVO csi300RankVO = new CSI300RankVO();
csi300RankVO.setCode(allCode.get(i).getCode());
csi300RankVO.setName(allCode.get(i).getName());
Double rise = (stockEntities.get(0).getClose_price() - stockEntities.get(stockEntities.size() - 1).getClose_price()) / stockEntities.get(stockEntities.size() - 1).getClose_price();
rise = rise * 100;
String str = String.format("%.2f", rise);
rise = Double.parseDouble(str);
csi300RankVO.setRise(rise);
csi300RankVOList.add(csi300RankVO);
}
log.info("填充数据");
// 将数据填充到缓存中
for (int i=0; i<csi300RankVOList.size(); i++) {
cache.add(csi300RankVOList.get(i));
}
} else {
log.info("缓存中已存在数据,不需要重新计算");
for (int i=0; i<cache.size(); i++) {
csi300RankVOList.add(cache.get(i));
}
}
// type==1查询涨幅
if (type == 1) {
// 按照涨幅升序排序
Collections.sort(csi300RankVOList, new Comparator<CSI300RankVO>() {
@Override
public int compare(CSI300RankVO o1, CSI300RankVO o2) {
if (o1.getRise() > o2.getRise()) {
return -1;
} else if (o1.getRise() == o2.getRise()) {
return 0;
} else {
return 1;
}
}
});
} else if (type == 2) { // type==2查询跌幅
Collections.sort(csi300RankVOList, new Comparator<CSI300RankVO>() {
@Override
public int compare(CSI300RankVO o1, CSI300RankVO o2) {
if (o1.getRise() > o2.getRise()) {
return 1;
} else if (o1.getRise() == o2.getRise()) {
return 0;
} else {
return -1;
}
}
});
}
// 最后取limit个数据返回
List<CSI300RankVO> result = new ArrayList<>();
for (int i=0; i<limit; i++) {
if (i > csi300RankVOList.size()-1) {
return result;
}
if (type == 1 && csi300RankVOList.get(i).getRise()<0) { // 查询涨幅
return result;
}
if (type == 2 && csi300RankVOList.get(i).getRise()>0) { // 查询跌幅
return result;
}
result.add(csi300RankVOList.get(i));
}
return result;
}
前端页面代码如下
<template>
<div>
<el-row class="container">
<div class="left-grid">
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>行业涨跌幅排行榜</span>
</div>
</template>
<el-table
v-loading="loading1"
:data="rise_data"
:show-header="true"
:max-height="250"
stripe
>
<el-table-column
type="index"
label="排名"
width="65%"
></el-table-column>
<el-table-column prop="industry" label="行业"></el-table-column>
<el-table-column
prop="rise"
label="涨幅"
:formatter="formatter1"
></el-table-column>
</el-table>
</el-card>
<el-card class="box-card">
<template #header>
<div class="card-header">
<span>行业权重</span>
</div>
</template>
<el-table
v-loading="loading2"
:data="industry_dist"
:show-header="true"
:max-height="250"
stripe
>
<el-table-column
type="index"
label="序号"
width="65%"
></el-table-column>
<el-table-column prop="industry" label="行业"></el-table-column>
<el-table-column
prop="weight"
label="权重"
:formatter="formatter2"
></el-table-column>
</el-table>
</el-card>
</div>
<div class="right-grid" ref="myChart"></div>
</el-row>
</div>
</template>
<script>
import axios from "axios";
import { getCurrentInstance } from "vue";
export default {
data() {
return {
// 涨幅排行榜
rise_data: [],
loading1: true,
// 权重数据
industry_dist: [],
loading2: true,
table_title: "行业涨跌幅排行榜",
echarts: getCurrentInstance().appContext.config.globalProperties.$echarts,
};
},
mounted() {
this.init();
},
methods: {
init() {
var url1 = "http://localhost:9001/stock/queryIndustryRank";
this.loading1 = true;
axios
.get(url1)
.then((response) => {
this.rise_data = response.data;
console.log(response);
this.loading1 = false;
this.create_bar();
})
.catch((error) => {
console.log(error);
this.loading1 = false;
});
var url2 = "http://localhost:9001/queryDist";
this.loading2 = true;
axios
.get(url2)
.then((response) => {
this.industry_dist = response.data;
console.log(response);
this.loading2 = false;
})
.catch((error) => {
console.log(error);
this.loading2 = false;
});
},
// 绘制柱状图
create_bar() {
//3.初始化实例对象 echarts.init(dom容器)
var data_xAxis = [];
var data_yAxis = [];
for (var i = this.rise_data.length - 1; i >= 0; i--) {
data_xAxis.push(this.rise_data[i].industry);
data_yAxis.push(this.rise_data[i].rise);
}
console.log(data_xAxis);
console.log(data_yAxis);
var dom = this.$refs["myChart"]; // 获取dom节点
var myChart = this.echarts.init(dom);
//4.指定配置项和数据
var option = {
tooltip: {
trigger: "axis",
position: function (pt) {
return [pt[0], "10%"];
},
},
title: {
left: "center",
text: this.table_title,
},
toolbox: {
feature: {
dataZoom: {
yAxisIndex: "none",
},
restore: {},
saveAsImage: {},
},
},
grid: {
top: 80,
bottom: 30,
},
xAxis: {
type: "value",
position: "top",
splitLine: {
lineStyle: {
type: "dashed",
},
},
},
yAxis: {
type: "category",
axisLine: { show: false },
axisLabel: { show: false },
axisTick: { show: false },
splitLine: { show: false },
data: data_xAxis,
},
series: [
{
name: "行业涨跌幅",
type: "bar",
stack: "Total",
label: {
show: true,
formatter: "[{b}]=>({c})%",
},
data: data_yAxis,
},
],
};
//5.将配置项设置给echarts实例对象,使用刚指定的配置项和数据显示图表。
myChart.setOption(option);
},
formatter1(row) {
return row.rise + "%";
},
formatter2(row) {
return row.weight + "%";
},
},
};
</script>
<style scoped>
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.container {
display: grid;
grid-template-columns: 35% 65%;
width: 100%;
height: 80vh;
}
.left-grid {
background-color: #f0f0f0;
border-radius: 2%;
padding: 10px;
height: 95%;
}
.right-grid {
background-color: #f9ecc3;
border-radius: 2%;
padding: 10px;
height: 650px;
}
</style>
最后计算得到的行业涨跌幅排行榜如下