目录
实现第二个接口:获取一段时间内,特定的股票每天的最大交易点的信息数据
我们现在要实现一个接口功能
查询当前时间下股票的涨跌幅度区间统计功能
如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
股票涨跌幅区间定义: "<-7%" 、 "-7~-5%"、 "-5~-3%" 、 "-3~0%" 、"0~3%" 、 "3~5%" 、 "5~7%" 、 ">7%"
要返回的数据
{ "code": 1, "data": { "time": "2021-12-31 14:58:00", "infos": [ { "count": 17, "title": "-3~0%" }, { "count": 2, "title": "-5~-3%" }, //省略...... ] } }
1.我们先书写sql语句
#统计当前时间下(精确到分钟),A股在各个涨跌区间股票的数量; #股票涨跌幅区间定义: "<-7%" 、 "-7~-5%"、 "-5~-3%" 、 "-3~0%" 、"0~3%" 、 "3~5%" 、 "5~7%" 、 ">7%" #1.使用的表stock_market_index_info #2.业务分析:1.时间:当前最新交易时间点 #2.要统计出每个个股的涨幅流水表 #3.把每个个股的涨幅转换成涨跌幅区间 使用 case when then end #4.最后根据涨跌幅区间来分组统计每个组的记录数量 count #3.返回的数据 count title(涨跌幅区间)
#1.统计每个个股的涨幅
select (cur_price-pre_close_price)/pre_close_price as ud from stock_rt_info where cur_time='2022-01-06 09:55:00';
#2.把涨幅字段的值转换成涨跌幅区间
select
case
when tmp.ud>0.07 then '>7%' #根据条件来该字段的值
when tmp.ud<=0.07 and tmp.ud>0.05 then '5~7%'
when tmp.ud<=0.05 and tmp.ud>0.03 then '3~5%'
when tmp.ud<=0.03 and tmp.ud>0 then '0~3%'
when tmp.ud<=0 and tmp.ud>-0.03 then '-3~0%'
when tmp.ud<=-0.03 and tmp.ud>-0.05 then '-5~-3%'
when tmp.ud<=-0.05 and tmp.ud>=-0.07 then '-7~-5%'
else '<-7%'
end 'title' #给这个字段重命名
from (select (cur_price-pre_close_price)/pre_close_price as ud from stock_rt_info where cur_time='2022-01-06 09:55:00')
as tmp;
#3.根据涨跌幅区间进行分组
select count(*) as count, tmp2.title from (select
case
when tmp.ud>0.07 then '>7%' #根据条件来该字段的值
when tmp.ud<=0.07 and tmp.ud>0.05 then '5~7%'
when tmp.ud<=0.05 and tmp.ud>0.03 then '3~5%'
when tmp.ud<=0.03 and tmp.ud>0 then '0~3%'
when tmp.ud<=0 and tmp.ud>-0.03 then '-3~0%'
when tmp.ud<=-0.03 and tmp.ud>-0.05 then '-5~-3%'
when tmp.ud<=-0.05 and tmp.ud>=-0.07 then '-7~-5%'
else '<-7%'
end 'title' #给这个字段重命名
from (select (cur_price-pre_close_price)/pre_close_price as ud from stock_rt_info where cur_time='2022-01-06 09:55:00')
as tmp) as tmp2 group by tmp2.title;
2.编写接口
/**
* 查询当前时间下股票的涨跌幅度区间统计功能
* 如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
* @return
*/
@ApiOperation("查询最新交易时间下股票的涨跌幅度区间中各个股票的数量")
@GetMapping("/stock/updown")
public R<Map<String,Object>> getStockUpDown(){//这里使用的是Object,因为每个键对应的类型不一样,一个是String,一个是List集合
return stockService.stockUpDownScopeCount();
}
3.书写业务逻辑
/**
* 查询当前时间下股票的涨跌幅度区间统计功能
* 如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
* @return
*/
@Override
public R<Map<String, Object>> stockUpDownScopeCount() {
//1.获取当前时间的最新交易点
DateTime datetime = DateTimeUtil.getLastDate4Stock(DateTime.now());
Date time=datetime.toDate();
//设置mock data
DateTime curDateTime=DateTime.parse("2022-01-06 09:55:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
Date curDate = curDateTime.toDate();
//2.根据mapper接口获取数据
List<Map> infos=stockRtInfoMapper.getStockUpDownScopeCount(curDate);
//3.封装数据
Map<String,Object>data=new HashMap<>();
data.put("time",curDateTime.toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")));
data.put("infos",infos);
//4.返回数据
return R.ok(data);
}
4.书写mapper
/**
* 查询当前时间下股票的涨跌幅度区间统计功能
* 如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
* @return
*/
List<Map> getStockUpDownScopeCount(@Param("curDate") Date curDate);
5.书写mapperXml文件
<!-- 如果在XML中SQL语句遇到大量特殊字符需要转义,比如:< 等,建议使用** sql 语句 **标记,这样特殊字符就不会被解析器解析
所以使用<![CDATA[]]> -->
<select id="getStockUpDownScopeCount" resultType="map">
<![CDATA[
select count(*) as count, tmp2.title from (select
case
when tmp.ud>0.07 then '>7%'
when tmp.ud<=0.07 and tmp.ud>0.05 then '5~7%'
when tmp.ud<=0.05 and tmp.ud>0.03 then '3~5%'
when tmp.ud<=0.03 and tmp.ud>0 then '0~3%'
when tmp.ud<=0 and tmp.ud>-0.03 then '-3~0%'
when tmp.ud<=-0.03 and tmp.ud>-0.05 then '-5~-3%'
when tmp.ud<=-0.05 and tmp.ud>=-0.07 then '-7~-5%'
else '<-7%'
end 'title'
from (select (cur_price-pre_close_price)/pre_close_price as ud from stock_rt_info where cur_time=#{curDate})
as tmp) as tmp2 group by tmp2.title
]]>
</select>
结果:
缺点:没有根据涨跌幅区间的大小来排序
我们可以在application-stock.yml文件中自己书写按照大小排序的涨跌幅区间,因为涨跌幅区间不能直接进行大小比较进行排序
1.yml文件
# 配置股票相关的参数
stock:
upDownRange:
- "<-7%"
- "-7~-5%"
- "-5~-3%"
- "-3~0%"
- "0~3%"
- "3~5%"
- "5~7%"
- ">7%"
2.在value object包下映射这个yml文件
@Data
@ConfigurationProperties(prefix = "stock")//映射yml文件中stock属性的值
//@Component//直接让其交给spring管理,TODO:我们不使用(不让它自己开启),我们让其他要使用该类的子模块来开启
public class StockInfoConfig {
public List<String>upDownRange;//涨跌幅区间
}
3.开启这个配置类进行映射,并把它交给spring管理
@Configuration
@EnableConfigurationProperties(StockInfoConfig.class)//TODO:在这个子模块开启加载此配置类,并让它映射yml文件中的stock属性的值,再交给spring管理
public class CommonConfig {
}
4.修改后的业务逻辑
/**
* 查询当前时间下股票的涨跌幅度区间统计功能
* 如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
* @return
*/
@Override
public R<Map<String, Object>> stockUpDownScopeCount() {
//1.获取当前时间的最新交易点
DateTime datetime = DateTimeUtil.getLastDate4Stock(DateTime.now());
Date time=datetime.toDate();
//设置mock data
DateTime curDateTime=DateTime.parse("2022-01-06 09:55:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
Date curDate = curDateTime.toDate();
//2.根据mapper接口获取数据
List<Map> infos=stockRtInfoMapper.getStockUpDownScopeCount(curDate);
//获取涨跌幅区间(按照大小排序)
List<String> upDownRange = stockInfoConfig.getUpDownRange();
List<Map>orderInfos=new ArrayList<>();//创建一个新的集合,来接收新的数据
for (String range : upDownRange) {//按照涨跌幅区间排序(升序)
Map tmpMap =null;//创建一个临时map
for (Map map : infos) {
if(map.containsValue(range)){//如果包含这个涨跌幅区间,就进行赋值
tmpMap=map;
break;
}
}
if(tmpMap==null) {//如果tmpMap还为null,则说明没有该涨跌幅区间
tmpMap=new HashMap();//自己进行赋值
tmpMap.put("count",0);
tmpMap.put("title",range);
}
orderInfos.add(tmpMap);//添加
}
//3.封装数据
Map<String,Object>data=new HashMap<>();
data.put("time",curDateTime.toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")));
data.put("infos",orderInfos);
//4.返回数据
return R.ok(data);
}
5.新的结果
6.第二种业务逻辑,使用lambda表达式
/**
* 查询当前时间下股票的涨跌幅度区间统计功能
* 如果当前日期不在有效时间内,则以最近的一个股票交易时间作为查询点
* @return
*/
@Override
public R<Map<String, Object>> stockUpDownScopeCount() {
//1.获取当前时间的最新交易点
DateTime datetime = DateTimeUtil.getLastDate4Stock(DateTime.now());
Date time=datetime.toDate();
//设置mock data
DateTime curDateTime=DateTime.parse("2022-01-06 09:55:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss"));
Date curDate = curDateTime.toDate();
//2.根据mapper接口获取数据
List<Map> infos=stockRtInfoMapper.getStockUpDownScopeCount(curDate);
//获取涨跌幅区间(按照大小排序)
List<String> upDownRange = stockInfoConfig.getUpDownRange();
/*
List<Map>orderInfos=new ArrayList<>();//创建一个新的集合,来接收新的数据
for (String range : upDownRange) {//按照涨跌幅区间排序(升序)
Map tmpMap =null;//创建一个临时map
for (Map map : infos) {
if(map.containsValue(range)){//如果包含这个涨跌幅区间,就进行赋值
tmpMap=map;
break;
}
}
if(tmpMap==null) {//如果tmpMap还为null,则说明没有该涨跌幅区间
tmpMap=new HashMap();//自己进行赋值
tmpMap.put("count",0);
tmpMap.put("title",range);
}
orderInfos.add(tmpMap);//添加
}
*/
List<Map>orderInfos=upDownRange.stream().map(range->{//使用map方法将String数据类型转换成map类型,range是upDownRange集合的每个值
Map tmpMap=null;//创建一个临时map
//使用之前查询出来的List<Map>集合来过滤出含有涨跌幅区间的map,并使用findFirst()进行赋值
//这里使用 Optional来接收,是防止为null
Optional<Map>op =infos.stream().filter(map->map.containsValue(range)).findFirst();
if(op.isPresent()){
tmpMap=op.get();//存在就直接进行赋值
}else{
tmpMap=new HashMap();//自己进行赋值
tmpMap.put("count",0);
tmpMap.put("title",range);
}
return tmpMap;
}).collect(Collectors.toList());
//3.封装数据
Map<String,Object>data=new HashMap<>();
data.put("time",curDateTime.toString(DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")));
data.put("infos",orderInfos);
//4.返回数据
return R.ok(data);
}
实现第二个接口:获取一段时间内,特定的股票每天的最大交易点的信息数据
1.返回的数据格式
{
"code": 1,
"data": [
{
"date": "2021-12-20 10:20",//日期
"tradeAmt": 28284252,//交易量(指收盘时的交易量,如果当天未收盘,则显示最新数据)
"code": "000021",//股票编码
"lowPrice": 16,//最低价格(指收盘时记录的最低价,如果当天未收盘,则显示最新数据)
"name": "深科技",//名称
"highPrice": 16.83,//最高价(指收盘时记录的最高价,如果当天未收盘,则显示最新数据)
"openPrice": 16.8,//开盘价
"tradeVol": 459088567.58,//交易金额(指收盘时记录交易量,如果当天未收盘,则显示最新数据)
"closePrice": 16.81//当前收盘价(指收盘时的价格,如果当天未收盘,则显示最新cur_price)
"preClosePrice": 16.81//前收盘价
},
//......
]
}
把data里面的key封装成一个domain包下的类,因为是通过与数据库进行交互并赋值的
2.domain类
/**
* @Description 个股日K数据封装
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ApiModel(description = "个股日K数据封装")
public class Stock4EvrDayDomain {
/**
* 日期,eg:202201280809
*/
@ApiModelProperty("当前日期")
@JsonFormat(pattern = "yyyy-MM-dd",timezone = "Asia/Shanghai")//设置返回给前端的时间数据格式
private Date date;
/**
* 交易量
*/
@ApiModelProperty("交易量")
private Long tradeAmt;
/**
* 股票编码
*/
@ApiModelProperty("股票编码")
private String code;
/**
* 最低价
*/
@ApiModelProperty("最低价")
private BigDecimal lowPrice;
/**
* 股票名称
*/
@ApiModelProperty("股票名称")
private String name;
/**
* 最高价
*/
@ApiModelProperty("最高价")
private BigDecimal highPrice;
/**
* 开盘价
*/
@ApiModelProperty("开盘价")
private BigDecimal openPrice;
/**
* 当前交易总金额
*/
@ApiModelProperty("当前交易总金额")
private BigDecimal tradeVol;
/**
* 当前收盘价格指收盘时的价格,如果当天未收盘,则显示最新cur_price)
*/
@ApiModelProperty("当前收盘价格指收盘时的价格,如果当天未收盘,则显示最新cur_price")
private BigDecimal closePrice;
/**
* 前收盘价
*/
@ApiModelProperty("前收盘价")
private BigDecimal preClosePrice;
}
3.sql语句分析
#1.需要使用的表stock_rt_info
#2.业务分析 1.规定一个时间范围,几天到几天 between and
#2.根据每天,即通过相同天数来分组 grouped by
#3.然后取每个组内的最大交易时间点来查询各个信息 根据 in
#1.找到一段时间范围内每天的特定股票的最大交易点
select max(cur_time) #取每个组的最大时间交易点
from stock_rt_info where cur_time between '2022-01-01 09:30:00' and '2022-06-06 14:25:00' and stock_code='600021'
group by date_format(cur_time,'%Y%m%d');#根据天数相同来分组,所以格式化时间,去掉时分秒
#2.根据每天的最大交易点来查询特定股票的数据
select
cur_time as date,
trade_amount as tradeAmt,
stock_code as code,
min_price as lowPrice,
stock_name as name,
max_price as highPrice,
open_price as openPrice,
trade_volume as tradeVol,
cur_price as closePrice,
pre_close_price as preClosePrice
from stock_rt_info
where stock_code='600009' and
cur_time in (select max(cur_time) #取每个组的最大时间交易点
from stock_rt_info where cur_time between '2022-01-01 09:30:00' and '2022-06-06 14:25:00' and stock_code='600021'
group by date_format(cur_time,'%Y%m%d')) order by cur_time;#根据时间大小进行排序
4.接口编写
/**
* 单个个股日K 数据查询 ,可以根据时间区间查询数日的K线数据
* @param stockCode 股票编码
*/
@GetMapping("/stock/screen/dkline")
@ApiOperation("单个个股日K 数据查询 ,可以根据时间区间查询数日的K线数据")
@ApiImplicitParams(
@ApiImplicitParam(name="code",value = "特定股票编码",required = true)
)
public R<List<Stock4EvrDayDomain>> getDayKLinData(@RequestParam(value = "code",required = true) String stockCode){
return stockService.stockCreenDkLine(stockCode);
}
5.业务逻辑
/**
* 获取一段时间内,特定的股票每天的最大交易点的信息数据
* @param stockCode 特定股票的编码
*/
@Override
public R<List<Stock4EvrDayDomain>> stockCreenDkLine(String stockCode) {
//获取当前的时间的最新交易点
DateTime datetime = DateTimeUtil.getLastDate4Stock(DateTime.now());
Date curTime = datetime.toDate();
//设置mock data
curTime = DateTime.parse("2022-06-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//获取十天前的时间
DateTime lastDateTime = datetime.minusDays(10);
Date lastTime = lastDateTime.toDate();
//设置mock data
lastTime=DateTime.parse("2022-01-01 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//调用接口mapper方法
List<Stock4EvrDayDomain>data= stockRtInfoMapper.getStockInfo4EvrDay(lastTime,curTime,stockCode);
if(data==null){
return R.error(ResponseCode.NO_RESPONSE_DATA);
}
//返回数据
return R.ok(data);
}
6.mapper
/**
* 获取一段时间内,每天的最大交易时间的特定股票的基本数据
* @param lastTime 一段时间的开头
* @param curTime 一段时间的末尾
* @param stockCode 特定股票编码
*/
List<Stock4EvrDayDomain> getStockInfo4EvrDay(@Param("lastTime") Date lastTime, @Param("curTime") Date curTime, @Param("stockCode") String stockCode);
7.mapperXml文件
<select id="getStockInfo4EvrDay" resultType="com.hhh.stock.pojo.domain.Stock4EvrDayDomain">
select
cur_time as date,
trade_amount as tradeAmt,
stock_code as code,
min_price as lowPrice,
stock_name as name,
max_price as highPrice,
open_price as openPrice,
trade_volume as tradeVol,
cur_price as closePrice,
pre_close_price as preClosePrice
from stock_rt_info
where stock_code=#{stockCode} and
cur_time in (select max(cur_time)
from stock_rt_info where cur_time between #{lastTime} and #{curTime} and stock_code=#{stockCode}
group by date_format(cur_time,'%Y%m%d')) order by cur_time
</select>
结果
把复杂的sql语句分步
1.mapper
/**
* 获取一段时间内特定股票的每天的最大交易时间点
* @param lastTime 一段时间的开始
* @param curTime 一段时间的末尾
* @param stockCode 特定股票的编码
*/
List<Date>getStockEvrDayOfMaxTradingTime(@Param("lastTime") Date lastTime, @Param("curTime") Date curTime, @Param("stockCode") String stockCode);
/**
* 根据每天的最大交易时间点来查询特定股票的信息
* @param dateList 每天的最大交易点的集合
* @param stockCode 特定的股票编码
*/
List<Stock4EvrDayDomain>getStockInfo4EvrDayByMaxTradingTime(@Param("dateList") List<Date>dateList, @Param("stockCode") String stockCode);
2.mapperXml文件
<select id="getStockEvrDayOfMaxTradingTime" resultType="java.util.Date">
select max(cur_time) as date from stock_rt_info where cur_time
between #{lastTime} and #{curTime} and stock_code=#{stockCode}
group by date_format(cur_time,'%Y%m%d')
</select>
<select id="getStockInfo4EvrDayByMaxTradingTime" resultType="com.hhh.stock.pojo.domain.Stock4EvrDayDomain">
select
cur_time as date,
trade_amount as tradeAmt,
stock_code as code,
min_price as lowPrice,
stock_name as name,
max_price as highPrice,
open_price as openPrice,
trade_volume as tradeVol,
cur_price as closePrice,
pre_close_price as preClosePrice
from stock_rt_info
where stock_code=#{stockCode} and
cur_time in
<foreach collection="dateList" item="date" open="(" separator="," close=")">
#{date}
</foreach>
order by cur_time
</select>
3.业务逻辑
/**
* 通过分解复杂sql语句来查询一段时间内的每天的最大交易点的特定股票的数据
* @param stockCode 特定股票的编码
*/
@Override
public R<List<Stock4EvrDayDomain>> stockCreenDkLine2(String stockCode) {
//获取当前的时间的最新交易点
DateTime datetime = DateTimeUtil.getLastDate4Stock(DateTime.now());
Date curTime = datetime.toDate();
//设置mock data
curTime = DateTime.parse("2022-06-06 14:25:00", DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//获取十天前的时间
DateTime lastDateTime = datetime.minusDays(10);
Date lastTime = lastDateTime.toDate();
//设置mock data
lastTime=DateTime.parse("2022-01-01 09:30:00",DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")).toDate();
//调用mapper来获取每天的最大交易点的集合
List<Date> dateList = stockRtInfoMapper.getStockEvrDayOfMaxTradingTime(lastTime, curTime, stockCode);
//调用mapper根据最大交易点的集合获取特定股票的信息
List<Stock4EvrDayDomain> data = stockRtInfoMapper.getStockInfo4EvrDayByMaxTradingTime(dateList, stockCode);
if(data==null){
return R.error(ResponseCode.NO_RESPONSE_DATA);
}
//返回数据
return R.ok(data);
}