├── src ├── main │ ├── resources │ │ └── application.yml │ └── java │ │ └── com │ │ └── fox │ │ └── spider │ │ └── stock │ │ ├── api │ │ ├── hk │ │ │ └── HKBaseApi.java │ │ ├── sh │ │ │ └── SHBaseApi.java │ │ ├── sz │ │ │ ├── SZBaseApi.java │ │ │ └── SZStockInfoApi.java │ │ ├── StockBaseApi.java │ │ ├── ifeng │ │ │ ├── IFengBaseApi.java │ │ │ ├── IFengRealtimePriceDealNumApi.java │ │ │ ├── IFengRealtimeBigDealApi.java │ │ │ ├── IFengKLineApi.java │ │ │ ├── IFengFiveDayMinuteScopeKLineApi.java │ │ │ └── IFengRealtimeDealDetailApi.java │ │ ├── sina │ │ │ ├── SinaBaseApi.java │ │ │ ├── SinaFQPriceLineApi.java │ │ │ ├── SinaPriceDealNumRatioApi.java │ │ │ ├── SinaRealtimePriceDealNumRatioApi.java │ │ │ ├── SinaMinuteKLineDataApi.java │ │ │ ├── SinaRealtimeDealDetailTimeScopeApi.java │ │ │ └── SinaRealtimeDealDetailApi.java │ │ ├── nets │ │ │ ├── NetsBaseApi.java │ │ │ ├── NetsFQTotalClosePriceApi.java │ │ │ └── NetsRealtimeMinuteKLineApi.java │ │ └── tencent │ │ │ ├── TencentRelateBlockApi.java │ │ │ ├── TencentBaseApi.java │ │ │ ├── TencentRelateStockApi.java │ │ │ ├── TencentKLineBaseApi.java │ │ │ ├── TencentRealtimeDealDetailTimeScopeApi.java │ │ │ └── TencentRealtimeMinuteKLineApi.java │ │ ├── entity │ │ ├── po │ │ │ ├── tencent │ │ │ │ ├── TenckentKLinePo.java │ │ │ │ ├── TencentRelateBlockPo.java │ │ │ │ ├── TencentRelateStockPo.java │ │ │ │ ├── TencentRealtimeMinuteNodeDataPo.java │ │ │ │ ├── TencentBigDealPo.java │ │ │ │ ├── TencentDayMinKLinePo.java │ │ │ │ ├── TencentRealtimePriceDealNumInfoPo.java │ │ │ │ ├── TencentFiveDayMinuteKLinePo.java │ │ │ │ ├── TencentRealtimePriceDealNumPo.java │ │ │ │ ├── TencentRealtimeDealDetailPo.java │ │ │ │ ├── TencentKLineNodeDataPo.java │ │ │ │ ├── TencentKLinePo.java │ │ │ │ ├── TencentMinuteScopeNodeDataPo.java │ │ │ │ ├── TencentMinuteScopeKLinePo.java │ │ │ │ ├── TencentRealtimeMinuteKLinePo.java │ │ │ │ └── TencentRealtimeDealInfoPo.java │ │ │ ├── ifeng │ │ │ │ ├── IFengRealtimeDealDetailPo.java │ │ │ │ ├── IFengRealtimePriceDealNumPo.java │ │ │ │ ├── IFengKLinePo.java │ │ │ │ ├── IFengRealtimeDealDetailDataPo.java │ │ │ │ ├── IFengFiveDayMinuteNodeDataPo.java │ │ │ │ ├── IFengRealtimeBigDealPo.java │ │ │ │ ├── IFengFiveDayMinuteScopeKLinePo.java │ │ │ │ ├── IFengFiveDayMinuteKLinePo.java │ │ │ │ └── IFengRealtimeDealInfoPo.java │ │ │ ├── hk │ │ │ │ ├── HKKLinePo.java │ │ │ │ ├── HKKLineNodeDataPo.java │ │ │ │ └── HKStockInfoPo.java │ │ │ ├── sina │ │ │ │ ├── SinaPriceDealNumRatioPo.java │ │ │ │ ├── SinaRealtimeDealDetailTimeScopePo.java │ │ │ │ ├── SinaRealtimeDealDetailTimeScopeDataPo.java │ │ │ │ ├── SinaMinuteKLineDataPo.java │ │ │ │ ├── SinaRealtimeDealDetailPo.java │ │ │ │ ├── SinaBigDealPo.java │ │ │ │ ├── SinaBigDealSumPo.java │ │ │ │ └── SinaRealtimeDealInfoPo.java │ │ │ ├── nets │ │ │ │ ├── NetsFQKLineDataPo.java │ │ │ │ ├── NetsRealtimeMinuteNodeDataPo.java │ │ │ │ ├── NetsFQKLineNodeDataPo.java │ │ │ │ ├── NetsRealtimeMinuteKLinePo.java │ │ │ │ ├── NetsDayDealInfoPo.java │ │ │ │ └── NetsRealtimeDealInfoPo.java │ │ │ ├── sz │ │ │ │ ├── SZKLinePo.java │ │ │ │ ├── SZRealtimeMinuteKLinePo.java │ │ │ │ ├── SZKLineNodeDataPo.java │ │ │ │ ├── SZStockInfoPo.java │ │ │ │ └── SZRealtimeDealPo.java │ │ │ └── sh │ │ │ │ ├── SHRealtimeMinuteNodeDataPo.java │ │ │ │ ├── SHRealtimeMinuteKLinePo.java │ │ │ │ ├── SHStockInfoPo.java │ │ │ │ └── SHRealtimeDealInfoPo.java │ │ ├── vo │ │ │ ├── sina │ │ │ │ ├── SinaBigDealSortVo.java │ │ │ │ └── SinaBigDealFilterVo.java │ │ │ ├── PageVo.java │ │ │ ├── StockCategoryVo.java │ │ │ └── StockVo.java │ │ └── dto │ │ │ └── http │ │ │ └── HttpResponseDto.java │ │ ├── StockApplication.java │ │ ├── service │ │ ├── StockToolService.java │ │ └── impl │ │ │ └── StockToolImpl.java │ │ ├── util │ │ ├── JSONUtil.java │ │ ├── CharsetUtil.java │ │ └── BigDecimalUtil.java │ │ └── constant │ │ └── StockMarketStatusConst.java └── test │ └── java │ └── com │ └── fox │ └── spider │ └── stock │ ├── StockApplicationTests.java │ ├── StockBaseTests.java │ ├── service │ └── StockToolServiceTests.java │ └── api │ ├── HKApiTests.java │ ├── SZApiTests.java │ ├── SHApiTests.java │ ├── NetsApiTests.java │ ├── IFengApiTests.java │ ├── SinaApiTests.java │ └── TencentApiTests.java ├── .gitignore └── pom.xml /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/hk/HKBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.hk; 2 | 3 | /** 4 | * 港股接口基类 5 | * 6 | * @author lusongsong 7 | * @date 2020/11/20 14:55 8 | */ 9 | public class HKBaseApi { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sh/SHBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sh; 2 | 3 | /** 4 | * 沪市接口基类 5 | * 6 | * @author lusongsong 7 | * @date 2020/11/19 18:11 8 | */ 9 | public class SHBaseApi { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sz/SZBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sz; 2 | 3 | /** 4 | * 深市接口基类 5 | * 6 | * @author lusongsong 7 | * @date 2020/11/20 14:28 8 | */ 9 | public class SZBaseApi { 10 | } 11 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TenckentKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | /** 4 | * @author lusongsong 5 | * @date 2020/12/28 18:43 6 | */ 7 | public class TenckentKLinePo { 8 | } 9 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/StockApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class StockApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/StockApplication.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class StockApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(StockApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRelateBlockPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 股票所属板块 9 | * 10 | * @author lusongsong 11 | * @date 2020/12/29 18:17 12 | */ 13 | @Data 14 | public class TencentRelateBlockPo implements Serializable { 15 | /** 16 | * 板块代码 17 | */ 18 | String code; 19 | /** 20 | * 板块名称 21 | */ 22 | String name; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/vo/sina/SinaBigDealSortVo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.vo.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 新浪股票交易日大单交易排序 9 | * 10 | * @author lusongsong 11 | * @date 2021/1/11 16:10 12 | */ 13 | @Data 14 | public class SinaBigDealSortVo implements Serializable { 15 | /** 16 | * 需要排序的属性 17 | */ 18 | String column = "ticktime"; 19 | /** 20 | * 是否为升序排序 21 | */ 22 | Integer asc = 0; 23 | } 24 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/vo/PageVo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * 分页对象信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/31 16:26 13 | */ 14 | @Data 15 | @AllArgsConstructor 16 | public class PageVo implements Serializable { 17 | /** 18 | * 页码 19 | */ 20 | Integer pageNum = 0; 21 | /** 22 | * 条数 23 | */ 24 | Integer pageSize = 20; 25 | } 26 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/**/target/ 5 | !**/src/test/**/target/ 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | !**/src/main/**/build/ 30 | !**/src/test/**/build/ 31 | 32 | ### VS Code ### 33 | .vscode/ 34 | 35 | ### MVN ### 36 | .mvn/ 37 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengRealtimeDealDetailPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 凤凰网交易明细信息 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/7 17:27 13 | */ 14 | @Data 15 | public class IFengRealtimeDealDetailPo implements Serializable { 16 | /** 17 | * 总页数 18 | */ 19 | Integer totalPageNum; 20 | /** 21 | * 交易明细列表 22 | */ 23 | List detailInfoList; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRelateStockPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 腾讯相关股票 9 | * 10 | * @author lusongsong 11 | * @date 2020/12/29 17:59 12 | */ 13 | @Data 14 | public class TencentRelateStockPo implements Serializable { 15 | /** 16 | * 股票所属交易所 17 | */ 18 | Integer stockMarket; 19 | /** 20 | * 股票代码 21 | */ 22 | String stockCode; 23 | /** 24 | * 股票名称 25 | */ 26 | String stockName; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/vo/sina/SinaBigDealFilterVo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.vo.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 新浪股票交易日大单交易筛选 9 | * 10 | * @author lusongsong 11 | * @date 2021/1/8 18:15 12 | */ 13 | @Data 14 | public class SinaBigDealFilterVo implements Serializable { 15 | /** 16 | * 成交量 17 | */ 18 | Integer dealNum = 0; 19 | /** 20 | * 成交金额 21 | */ 22 | Integer dealMoney = 0; 23 | /** 24 | * 倍数 25 | */ 26 | Integer times = 0; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengRealtimePriceDealNumPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * @author lusongsong 10 | * @date 2021/1/7 18:30 11 | */ 12 | @Data 13 | public class IFengRealtimePriceDealNumPo implements Serializable { 14 | /** 15 | * 成交价 16 | */ 17 | BigDecimal price; 18 | /** 19 | * 成交量 20 | */ 21 | Long dealNum; 22 | /** 23 | * 占比 24 | */ 25 | BigDecimal ratio; 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/hk/HKKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.hk; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 港股K线数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/12 19:16 13 | */ 14 | @Data 15 | public class HKKLinePo implements Serializable { 16 | /** 17 | * 股票代码 18 | */ 19 | String stockCode; 20 | /** 21 | * 股票所属交易所 22 | */ 23 | Integer stockMarket; 24 | /** 25 | * K线数据 26 | */ 27 | List klineData; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaPriceDealNumRatioPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 价格成交量占比数据 10 | * @author lusongsong 11 | * @date 2020/11/5 14:11 12 | */ 13 | @Data 14 | public class SinaPriceDealNumRatioPo implements Serializable { 15 | /** 16 | * 价格 17 | */ 18 | BigDecimal price; 19 | /** 20 | * 成交量 21 | */ 22 | Long dealNum; 23 | /** 24 | * 占比 25 | */ 26 | BigDecimal ratio; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaRealtimeDealDetailTimeScopePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 新浪网股票最新交易日交易明细时间范围 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/8 16:21 13 | */ 14 | @Data 15 | public class SinaRealtimeDealDetailTimeScopePo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 时间范围列表 22 | */ 23 | List timeScopeList; 24 | } 25 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaRealtimeDealDetailTimeScopeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | 7 | /** 8 | * 新浪网股票最新交易日交易明细时间范围详情 9 | * 10 | * @author lusongsong 11 | * @date 2021/1/8 16:26 12 | */ 13 | @Data 14 | public class SinaRealtimeDealDetailTimeScopeDataPo implements Serializable { 15 | /** 16 | * 页码 17 | */ 18 | Integer pageNum; 19 | /** 20 | * 开始时间 21 | */ 22 | String startTime; 23 | /** 24 | * 结束时间 25 | */ 26 | String endTime; 27 | } 28 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsFQKLineDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 网易复权类型k线数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/6 14:42 13 | */ 14 | @Data 15 | public class NetsFQKLineDataPo implements Serializable { 16 | /** 17 | * 股票代码 18 | */ 19 | String stockCode; 20 | /** 21 | * 股票名称 22 | */ 23 | String stockName; 24 | /** 25 | * 线图信息 26 | */ 27 | List klineData; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimeMinuteNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 腾讯实时交易分钟交易数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/25 14:58 13 | */ 14 | @Data 15 | public class TencentRealtimeMinuteNodeDataPo implements Serializable { 16 | /** 17 | * 分钟小时时间 18 | */ 19 | String time; 20 | /** 21 | * 价格 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 成交量 26 | */ 27 | Long dealNum; 28 | } 29 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsRealtimeMinuteNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 网易实时交易分钟交易数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/6 15:28 13 | */ 14 | @Data 15 | public class NetsRealtimeMinuteNodeDataPo implements Serializable { 16 | /** 17 | * 分钟小时时间 18 | */ 19 | String time; 20 | /** 21 | * 价格 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 均价 26 | */ 27 | BigDecimal avgPrice; 28 | /** 29 | * 成交量 30 | */ 31 | Long dealNum; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/service/StockToolService.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.service; 2 | 3 | import com.fox.spider.stock.entity.vo.StockVo; 4 | 5 | import java.math.BigDecimal; 6 | 7 | /** 8 | * 股票相关工具 9 | * 10 | * @author lusongsong 11 | * @date 2020/11/24 11:55 12 | */ 13 | public interface StockToolService { 14 | /** 15 | * 获取最新交易日 16 | * 17 | * @param stockMarket 18 | * @return 19 | */ 20 | String lastDealDate(Integer stockMarket); 21 | 22 | /** 23 | * 获取涨跌幅限制 24 | * 25 | * @param stockVo 26 | * @param stockName 27 | * @return 28 | */ 29 | BigDecimal limitRate(StockVo stockVo, String stockName); 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentBigDealPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 大单交易信息 10 | * @author lusongsong 11 | * @date 2020/12/31 15:49 12 | */ 13 | @Data 14 | public class TencentBigDealPo implements Serializable { 15 | /** 16 | * 时间 17 | */ 18 | String time; 19 | /** 20 | * 价格 21 | */ 22 | BigDecimal price; 23 | /** 24 | * 成交量 25 | */ 26 | Long dealNum; 27 | /** 28 | * 成交金额 29 | */ 30 | BigDecimal dealMoney; 31 | /** 32 | * 性质 33 | */ 34 | Integer dealType; 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentDayMinKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 腾讯按天分钟K线交易数据 11 | * 12 | * @author lusongsong 13 | * @date 2020/12/28 15:57 14 | */ 15 | @Data 16 | public class TencentDayMinKLinePo implements Serializable { 17 | /** 18 | * 日期 19 | */ 20 | String dt; 21 | /** 22 | * 昨日收盘价 23 | */ 24 | BigDecimal preClosePrice; 25 | /** 26 | * 线图的点数量 27 | */ 28 | Integer nodeCount; 29 | /** 30 | * 分钟粒度的成交信息 31 | */ 32 | List klineData; 33 | } 34 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/StockBaseTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.vo.StockVo; 5 | 6 | /** 7 | * 股票测试基类 8 | * 9 | * @author lusongsong 10 | * @date 2020/11/20 14:16 11 | */ 12 | public class StockBaseTests { 13 | /** 14 | * 沪市测试股票(顶点软件) 15 | */ 16 | public static final StockVo TEST_SH_STOCK = new StockVo("603383",StockConst.SM_SH); 17 | /** 18 | * 深市测试股票(同花顺) 19 | */ 20 | public static final StockVo TEST_SZ_STOCK = new StockVo("300033", StockConst.SM_SZ); 21 | /** 22 | * 港股测试股票(腾讯控股) 23 | */ 24 | public static final StockVo TEST_HK_STOCK = new StockVo("00700", StockConst.SM_HK); 25 | } 26 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimePriceDealNumInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 腾讯实时价格成交量信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/29 17:23 13 | */ 14 | @Data 15 | public class TencentRealtimePriceDealNumInfoPo implements Serializable { 16 | /** 17 | * 价格 18 | */ 19 | BigDecimal price; 20 | /** 21 | * 成交量 22 | */ 23 | Long dealNum; 24 | /** 25 | * 买入量 26 | */ 27 | Long buyDealNum; 28 | /** 29 | * 卖出量 30 | */ 31 | Long sellDealNum; 32 | /** 33 | * 中性量 34 | */ 35 | Long flatDealNum; 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/vo/StockCategoryVo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.vo; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import lombok.AllArgsConstructor; 5 | import lombok.Data; 6 | import lombok.NoArgsConstructor; 7 | 8 | import java.io.Serializable; 9 | 10 | /** 11 | * 股票所属分类 12 | * 13 | * @author lusongsong 14 | * @date 2020/11/12 15:35 15 | */ 16 | @Data 17 | @AllArgsConstructor 18 | @NoArgsConstructor 19 | public class StockCategoryVo implements Serializable { 20 | /** 21 | * 股市 22 | */ 23 | Integer stockMarket = StockConst.SM_UNKNOWN; 24 | /** 25 | * 类型 26 | */ 27 | Integer stockType = StockConst.ST_UNKNOWN; 28 | /** 29 | * 分类 30 | */ 31 | Integer stockKind = StockConst.SK_UNKNOWN; 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 凤凰网K线交易数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/6 16:50 13 | */ 14 | @Data 15 | public class IFengKLinePo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 开盘价 22 | */ 23 | BigDecimal openPrice; 24 | /** 25 | * 收盘价 26 | */ 27 | BigDecimal closePrice; 28 | /** 29 | * 最高价 30 | */ 31 | BigDecimal highestPrice; 32 | /** 33 | * 最低价 34 | */ 35 | BigDecimal lowestPrice; 36 | /** 37 | * 成交金额 38 | */ 39 | BigDecimal dealMoney; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengRealtimeDealDetailDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 凤凰网交易明细详情信息 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/7 17:51 13 | */ 14 | @Data 15 | public class IFengRealtimeDealDetailDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 时间 22 | */ 23 | String time; 24 | /** 25 | * 成交价 26 | */ 27 | BigDecimal price; 28 | /** 29 | * 成交量 30 | */ 31 | Long dealNum; 32 | /** 33 | * 成交金额 34 | */ 35 | BigDecimal dealMoney; 36 | /** 37 | * 性质 38 | */ 39 | Integer dealType; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sz/SZKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sz; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 深证股票K线数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/12 17:23 13 | */ 14 | @Data 15 | public class SZKLinePo implements Serializable { 16 | /** 17 | * 股票所属交易所 18 | */ 19 | Integer stockMarket; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName; 28 | /** 29 | * 线图类型 30 | */ 31 | Integer kLineType; 32 | /** 33 | * 线图的点数量 34 | */ 35 | Integer nodeCount; 36 | /** 37 | * 分钟粒度的成交信息 38 | */ 39 | List klineData; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sh/SHRealtimeMinuteNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sh; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 分钟线图数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/12 10:56 13 | */ 14 | @Data 15 | public class SHRealtimeMinuteNodeDataPo implements Serializable { 16 | /** 17 | * 时间 18 | */ 19 | String time; 20 | /** 21 | * 价格 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 成交量 26 | */ 27 | Long dealNum; 28 | /** 29 | * 成交金额 30 | */ 31 | BigDecimal dealMoney; 32 | /** 33 | * 价格涨幅 34 | */ 35 | BigDecimal uptickPrice; 36 | /** 37 | * 增长率 38 | */ 39 | BigDecimal uptickRate; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentFiveDayMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 腾讯5日分钟K线交易数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/28 15:54 13 | */ 14 | @Data 15 | public class TencentFiveDayMinuteKLinePo implements Serializable { 16 | /** 17 | * 股票所属交易所 18 | */ 19 | Integer stockMarket; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName; 28 | /** 29 | * 最新交易日交易详情 30 | */ 31 | TencentRealtimeDealInfoPo realtimeDealInfo; 32 | /** 33 | * 分钟粒度的成交信息 34 | */ 35 | List klineData; 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/vo/StockVo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.vo; 2 | 3 | import lombok.AllArgsConstructor; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * 股票基本信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/4 15:45 13 | */ 14 | @Data 15 | @AllArgsConstructor 16 | public class StockVo implements Serializable { 17 | /** 18 | * 股票代码 19 | */ 20 | String stockCode; 21 | /** 22 | * 股票所属交易所 23 | */ 24 | Integer stockMarket; 25 | 26 | /** 27 | * 验证对象是否正确 28 | * 29 | * @param stockVo 30 | * @return 31 | */ 32 | public static final boolean verify(StockVo stockVo) { 33 | return null != stockVo && null != stockVo.getStockMarket() && null != stockVo.getStockCode(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengFiveDayMinuteNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 凤凰网5天分钟数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/6 17:32 13 | */ 14 | @Data 15 | public class IFengFiveDayMinuteNodeDataPo implements Serializable { 16 | /** 17 | * 时间 18 | */ 19 | String time; 20 | /** 21 | * 价格 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 涨跌幅 26 | */ 27 | BigDecimal uptickRate; 28 | /** 29 | * 成交金额 30 | */ 31 | BigDecimal dealMoney; 32 | /** 33 | * 均价 34 | */ 35 | BigDecimal avgPrice; 36 | /** 37 | * 量比 38 | */ 39 | BigDecimal qrrRate; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimePriceDealNumPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.util.List; 7 | 8 | /** 9 | * 腾讯实时价格成交量 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/29 17:11 13 | */ 14 | @Data 15 | public class TencentRealtimePriceDealNumPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 成交量 22 | */ 23 | Long dealNum; 24 | /** 25 | * 买入量 26 | */ 27 | Long buyDealNum; 28 | /** 29 | * 卖出量 30 | */ 31 | Long sellDealNum; 32 | /** 33 | * 中性量 34 | */ 35 | Long flatDealNum; 36 | /** 37 | * 价格成交量 38 | */ 39 | List priceDealNumList; 40 | } 41 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengRealtimeBigDealPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 凤凰网大单交易 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/7 15:29 13 | */ 14 | @Data 15 | public class IFengRealtimeBigDealPo implements Serializable { 16 | /** 17 | * 时间 18 | */ 19 | String time; 20 | /** 21 | * 成交价 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 成交量 26 | */ 27 | Long dealNum; 28 | /** 29 | * 成交金额 30 | */ 31 | BigDecimal dealMoney; 32 | /** 33 | * 性质 34 | */ 35 | Integer dealType; 36 | /** 37 | * 价格涨幅 38 | */ 39 | BigDecimal uptickPrice; 40 | /** 41 | * 增长率 42 | */ 43 | BigDecimal uptickRate; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaMinuteKLineDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 分钟粒度成交数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/4 16:43 13 | */ 14 | @Data 15 | public class SinaMinuteKLineDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 时间 22 | */ 23 | String time; 24 | /** 25 | * 开盘价 26 | */ 27 | BigDecimal openPrice; 28 | /** 29 | * 收盘价 30 | */ 31 | BigDecimal closePrice; 32 | /** 33 | * 最高价 34 | */ 35 | BigDecimal highestPrice; 36 | /** 37 | * 最低价 38 | */ 39 | BigDecimal lowestPrice; 40 | /** 41 | * 成交数量 42 | */ 43 | Long dealNum; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimeDealDetailPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 交易明细数据 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/29 15:37 13 | */ 14 | @Data 15 | public class TencentRealtimeDealDetailPo implements Serializable { 16 | /** 17 | * 序号 18 | */ 19 | Integer num; 20 | /** 21 | * 时间 22 | */ 23 | String time; 24 | /** 25 | * 成交价格 26 | */ 27 | BigDecimal price; 28 | /** 29 | * 价格差异 30 | */ 31 | BigDecimal uptickPrice; 32 | /** 33 | * 成交量 34 | */ 35 | Long dealNum; 36 | /** 37 | * 成交金额 38 | */ 39 | BigDecimal dealMoney; 40 | /** 41 | * 性质 42 | */ 43 | Integer dealType; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsFQKLineNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 网易复权类型k线数据点 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/6 14:42 13 | */ 14 | @Data 15 | public class NetsFQKLineNodeDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 开盘价 22 | */ 23 | BigDecimal openPrice; 24 | /** 25 | * 收盘价 26 | */ 27 | BigDecimal closePrice; 28 | /** 29 | * 最高价 30 | */ 31 | BigDecimal highestPrice; 32 | /** 33 | * 最低价 34 | */ 35 | BigDecimal lowestPrice; 36 | /** 37 | * 成交数量 38 | */ 39 | Long dealNum; 40 | /** 41 | * 增幅 42 | */ 43 | BigDecimal uptickRate; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaRealtimeDealDetailPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 新浪网交易明细数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/8 16:57 13 | */ 14 | @Data 15 | public class SinaRealtimeDealDetailPo implements Serializable { 16 | /** 17 | * 时间 18 | */ 19 | String time; 20 | /** 21 | * 成交价格 22 | */ 23 | BigDecimal price; 24 | /** 25 | * 涨跌幅 26 | */ 27 | BigDecimal uptickRate; 28 | /** 29 | * 价格变动 30 | */ 31 | BigDecimal uptickPrice; 32 | /** 33 | * 成交量 34 | */ 35 | Long dealNum; 36 | /** 37 | * 成交金额 38 | */ 39 | BigDecimal dealMoney; 40 | /** 41 | * 交易类型 42 | */ 43 | Integer dealType; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentKLineNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 腾信k线图点交易信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/12/29 14:21 13 | */ 14 | @Data 15 | public class TencentKLineNodeDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 开盘价 22 | */ 23 | BigDecimal openPrice; 24 | /** 25 | * 最高价 26 | */ 27 | BigDecimal highestPrice; 28 | /** 29 | * 最低价 30 | */ 31 | BigDecimal lowestPrice; 32 | /** 33 | * 收盘价 34 | */ 35 | BigDecimal closePrice; 36 | /** 37 | * 成交量 38 | */ 39 | Long dealNum; 40 | /** 41 | * 成交额 42 | */ 43 | BigDecimal dealMoney; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaBigDealPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * @author lusongsong 10 | * @date 2021/1/11 15:39 11 | */ 12 | @Data 13 | public class SinaBigDealPo implements Serializable { 14 | /** 15 | * 股票所属交易所 16 | */ 17 | Integer stockMarket; 18 | /** 19 | * 股票代码 20 | */ 21 | String stockCode; 22 | /** 23 | * 股票名称 24 | */ 25 | String stockName; 26 | /** 27 | * 时间 28 | */ 29 | String time; 30 | /** 31 | * 价格 32 | */ 33 | BigDecimal price; 34 | /** 35 | * 之前价格 36 | */ 37 | BigDecimal prePrice; 38 | /** 39 | * 成交量 40 | */ 41 | Long dealNum; 42 | /** 43 | * 性质 44 | */ 45 | Integer dealType; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengFiveDayMinuteScopeKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 凤凰网5日分钟K线交易数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/6 16:50 13 | */ 14 | @Data 15 | public class IFengFiveDayMinuteScopeKLinePo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 分钟小时时间 22 | */ 23 | String time; 24 | /** 25 | * 开盘价 26 | */ 27 | BigDecimal openPrice; 28 | /** 29 | * 收盘价 30 | */ 31 | BigDecimal closePrice; 32 | /** 33 | * 最高价 34 | */ 35 | BigDecimal highestPrice; 36 | /** 37 | * 最低价 38 | */ 39 | BigDecimal lowestPrice; 40 | /** 41 | * 成交金额 42 | */ 43 | BigDecimal dealMoney; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sz/SZRealtimeMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sz; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * @author lusongsong 10 | * @date 2021/1/12 16:18 11 | */ 12 | @Data 13 | public class SZRealtimeMinuteKLinePo implements Serializable { 14 | /** 15 | * 时间 16 | */ 17 | String time; 18 | /** 19 | * 价格 20 | */ 21 | BigDecimal price; 22 | /** 23 | * 均价 24 | */ 25 | BigDecimal avgPrice; 26 | /** 27 | * 价格涨幅 28 | */ 29 | BigDecimal uptickPrice; 30 | /** 31 | * 增长率 32 | */ 33 | BigDecimal uptickRate; 34 | /** 35 | * 成交量 36 | */ 37 | Long dealNum; 38 | /** 39 | * 成交金额 40 | */ 41 | BigDecimal dealMoney; 42 | /** 43 | * 交易规模 44 | */ 45 | String dealScale; 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/hk/HKKLineNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.hk; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 港股K线数据点数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/13 11:16 13 | */ 14 | @Data 15 | public class HKKLineNodeDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 时间 22 | */ 23 | String time; 24 | /** 25 | * 收盘价 26 | */ 27 | BigDecimal closePrice; 28 | /** 29 | * 开盘价 30 | */ 31 | BigDecimal openPrice; 32 | /** 33 | * 最高价 34 | */ 35 | BigDecimal highestPrice; 36 | /** 37 | * 最低价 38 | */ 39 | BigDecimal lowestPrice; 40 | /** 41 | * 成交量 42 | */ 43 | Long dealNum; 44 | /** 45 | * 成交金额 46 | */ 47 | BigDecimal dealMoney; 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 腾信k线图 11 | * 12 | * @author lusongsong 13 | * @date 2020/12/29 14:20 14 | */ 15 | @Data 16 | public class TencentKLinePo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName; 29 | /** 30 | * 线图类型 31 | */ 32 | Integer kLineType; 33 | /** 34 | * 线图的点数量 35 | */ 36 | Integer nodeCount; 37 | /** 38 | * 昨日收盘价 39 | */ 40 | BigDecimal preClosePrice; 41 | /** 42 | * 分钟粒度的成交信息 43 | */ 44 | List klineData; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentMinuteScopeNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | import org.apache.commons.lang3.StringUtils; 5 | 6 | import java.io.Serializable; 7 | import java.math.BigDecimal; 8 | 9 | /** 10 | * 腾讯分钟粒度交易数据 11 | * @author lusongsong 12 | * @date 2020/12/28 16:59 13 | */ 14 | @Data 15 | public class TencentMinuteScopeNodeDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 时间 22 | */ 23 | String time; 24 | /** 25 | * 开盘价 26 | */ 27 | BigDecimal openPrice; 28 | /** 29 | * 最高价 30 | */ 31 | BigDecimal highestPrice; 32 | /** 33 | * 最低价 34 | */ 35 | BigDecimal lowestPrice; 36 | /** 37 | * 收盘价 38 | */ 39 | BigDecimal closePrice; 40 | /** 41 | * 成交量 42 | */ 43 | Long dealNum; 44 | } 45 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentMinuteScopeKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 腾讯分钟粒度线图信息 11 | * 12 | * @author lusongsong 13 | * @date 2020/12/28 16:59 14 | */ 15 | @Data 16 | public class TencentMinuteScopeKLinePo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName; 29 | /** 30 | * 线图的点数量 31 | */ 32 | Integer nodeCount; 33 | /** 34 | * 昨日收盘价 35 | */ 36 | BigDecimal preClosePrice; 37 | /** 38 | * 最新交易日交易详情 39 | */ 40 | TencentRealtimeDealInfoPo realtimeDealInfo; 41 | /** 42 | * 分钟粒度的成交信息 43 | */ 44 | List klineData; 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/StockBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | /** 4 | * 股票接口基类 5 | * 6 | * @author lusongsong 7 | * @date 2021/1/4 16:41 8 | */ 9 | public class StockBaseApi { 10 | /** 11 | * json字符传的起始字符 12 | */ 13 | public static final char JSON_OBJECT_START_CHAR = '{'; 14 | /** 15 | * json字符传的结束字符 16 | */ 17 | public static final char JSON_OBJECT_END_CHAR = '}'; 18 | 19 | /** 20 | * 去掉json对象字符串2边多余字符 21 | * 22 | * @param jsonStr 23 | * @return 24 | */ 25 | public static String trimJsonObject(String jsonStr) { 26 | if (null == jsonStr || jsonStr.isEmpty()) { 27 | return null; 28 | } 29 | int startPos = jsonStr.indexOf(JSON_OBJECT_START_CHAR); 30 | int endPos = jsonStr.lastIndexOf(JSON_OBJECT_END_CHAR); 31 | if (-1 != startPos && -1 != endPos) { 32 | return jsonStr.substring(startPos, endPos + 1); 33 | } 34 | return null; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsRealtimeMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 网易实时交易分钟线图数据 11 | * 12 | * @author lusongsong 13 | * @date 2020/11/6 15:22 14 | */ 15 | @Data 16 | public class NetsRealtimeMinuteKLinePo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName; 29 | /** 30 | * 日期 31 | */ 32 | String dt; 33 | /** 34 | * 线图的点数量 35 | */ 36 | Integer nodeCount; 37 | /** 38 | * 昨日收盘价 39 | */ 40 | BigDecimal preClosePrice; 41 | /** 42 | * 成交股数 43 | */ 44 | Long dealNum; 45 | /** 46 | * 分钟粒度的成交信息 47 | */ 48 | List klineData; 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengFiveDayMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 凤凰网5日分钟K线交易数据 11 | * 12 | * @author lusongsong 13 | * @date 2021/1/6 16:50 14 | */ 15 | @Data 16 | public class IFengFiveDayMinuteKLinePo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 日期 27 | */ 28 | String dt; 29 | /** 30 | * 开盘价 31 | */ 32 | BigDecimal openPrice; 33 | /** 34 | * 收盘价 35 | */ 36 | BigDecimal preClosePrice; 37 | /** 38 | * 最高价 39 | */ 40 | BigDecimal highestPrice; 41 | /** 42 | * 最低价 43 | */ 44 | BigDecimal lowestPrice; 45 | /** 46 | * 分钟数据 47 | */ 48 | List klineData; 49 | } 50 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/service/StockToolServiceTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.service; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.constant.StockConst; 5 | import org.junit.jupiter.api.Test; 6 | import org.springframework.beans.factory.annotation.Autowired; 7 | import org.springframework.boot.test.context.SpringBootTest; 8 | 9 | /** 10 | * 股票工具类测试 11 | * 12 | * @author lusongsong 13 | * @date 2020/11/24 17:26 14 | */ 15 | @SpringBootTest 16 | public class StockToolServiceTests extends StockBaseTests { 17 | /** 18 | * 股票工具类 19 | */ 20 | @Autowired 21 | StockToolService stockToolService; 22 | 23 | /** 24 | * 获取最新交易日测试 25 | */ 26 | @Test 27 | public void lastDealDate() { 28 | System.out.println(stockToolService.lastDealDate(StockConst.SM_A)); 29 | } 30 | 31 | /** 32 | * 涨跌幅限制测试 33 | */ 34 | @Test 35 | public void limitRate() { 36 | System.out.println(stockToolService.limitRate(TEST_SH_STOCK, "顶点软件")); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/util/JSONUtil.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.util; 2 | 3 | import org.apache.commons.lang3.StringUtils; 4 | 5 | /** 6 | * JSON工具类 7 | * 8 | * @author lusongsong 9 | * @date 2021/1/13 10:57 10 | */ 11 | public class JSONUtil { 12 | /** 13 | * JSON对象的起始字符 14 | */ 15 | public static final char JSON_OBJECT_START_CHAR = '{'; 16 | /** 17 | * JSON对象的结束字符 18 | */ 19 | public static final char JSON_OBJECT_END_CHAR = '}'; 20 | 21 | /** 22 | * 去除JSON对象字符串2边的多余字符 23 | * 24 | * @param jsonStr 25 | * @return 26 | */ 27 | public static String objectStrTrim(String jsonStr) { 28 | if (!StringUtils.isEmpty(jsonStr)) { 29 | int startPos = jsonStr.indexOf(JSON_OBJECT_START_CHAR); 30 | int endPos = jsonStr.lastIndexOf(JSON_OBJECT_END_CHAR); 31 | if (-1 != startPos && -1 != endPos && startPos < endPos) { 32 | return jsonStr.substring(startPos, endPos + 1); 33 | } 34 | } 35 | return ""; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sh/SHRealtimeMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sh; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 上证股票最新交易日分钟线图数据 11 | * 12 | * @author lusongsong 13 | * @date 2021/1/12 10:46 14 | */ 15 | @Data 16 | public class SHRealtimeMinuteKLinePo implements Serializable { 17 | /** 18 | * 股票代码 19 | */ 20 | String stockCode; 21 | /** 22 | * 股票所属交易所 23 | */ 24 | Integer stockMarket; 25 | /** 26 | * 日期 27 | */ 28 | String dt; 29 | /** 30 | * 时间 31 | */ 32 | String time; 33 | /** 34 | * 上个交易日收盘价 35 | */ 36 | BigDecimal preClosePrice; 37 | /** 38 | * 最高价 39 | */ 40 | BigDecimal highestPrice; 41 | /** 42 | * 最低价 43 | */ 44 | BigDecimal lowestPrice; 45 | /** 46 | * 分钟点数 47 | */ 48 | Integer nodeCount; 49 | /** 50 | * 分钟粒度的成交信息 51 | */ 52 | List klineData; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sz/SZKLineNodeDataPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sz; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 深证股票k线数据 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/12 17:24 13 | */ 14 | @Data 15 | public class SZKLineNodeDataPo implements Serializable { 16 | /** 17 | * 日期 18 | */ 19 | String dt; 20 | /** 21 | * 开盘价格 22 | */ 23 | BigDecimal openPrice; 24 | /** 25 | * 最高价 26 | */ 27 | BigDecimal highestPrice; 28 | /** 29 | * 最低价 30 | */ 31 | BigDecimal lowestPrice; 32 | /** 33 | * 收盘价 34 | */ 35 | BigDecimal closePrice; 36 | /** 37 | * 价格涨幅 38 | */ 39 | BigDecimal uptickPrice; 40 | /** 41 | * 增长率 42 | */ 43 | BigDecimal uptickRate; 44 | /** 45 | * 成交量 46 | */ 47 | Long dealNum; 48 | /** 49 | * 成交金额 50 | */ 51 | BigDecimal dealMoney; 52 | /** 53 | * 交易规模 54 | */ 55 | String dealScale; 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimeMinuteKLinePo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | 9 | /** 10 | * 股票实时交易分钟线图数据 11 | * 12 | * @author lusongsong 13 | * @date 2020/12/25 14:58 14 | */ 15 | @Data 16 | public class TencentRealtimeMinuteKLinePo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName; 29 | /** 30 | * 日期 31 | */ 32 | String dt; 33 | /** 34 | * 线图的点数量 35 | */ 36 | Integer nodeCount; 37 | /** 38 | * 昨日收盘价 39 | */ 40 | BigDecimal preClosePrice; 41 | /** 42 | * 成交股数 43 | */ 44 | Long dealNum; 45 | /** 46 | * 最新交易日交易详情 47 | */ 48 | TencentRealtimeDealInfoPo realtimeDealInfo; 49 | /** 50 | * 分钟粒度的成交信息 51 | */ 52 | List klineData; 53 | } 54 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/hk/HKStockInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.hk; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * 港股股票信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/20 14:57 13 | */ 14 | @Data 15 | public class HKStockInfoPo implements Serializable { 16 | /** 17 | * 股票所属交易所 18 | */ 19 | Integer stockMarket = StockConst.SM_HK; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode = ""; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName = ""; 28 | /** 29 | * 股票全称 30 | */ 31 | String stockFullName = ""; 32 | /** 33 | * 公司法人代表 34 | */ 35 | String stockLegal = ""; 36 | /** 37 | * 股票公司注册地址 38 | */ 39 | String stockRegisterAddress = ""; 40 | /** 41 | * 股票公司通讯地址 42 | */ 43 | String stockConnectAddress = ""; 44 | /** 45 | * 股票上市日期 46 | */ 47 | String stockOnDate = ""; 48 | /** 49 | * 股票总股本(万) 50 | */ 51 | Double stockTotalEquity = 0.0; 52 | /** 53 | * 股票流通股本(万) 54 | */ 55 | Double stockCircEquity = 0.0; 56 | /** 57 | * 股票所属行业 58 | */ 59 | String stockIndustry = ""; 60 | /** 61 | * 股票CSRC行业(门类/大类/中类) 62 | */ 63 | String stockCarc = ""; 64 | } 65 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/HKApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.hk.HKKLineApi; 5 | import com.fox.spider.stock.api.hk.HKStockInfoApi; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | /** 11 | * 香港交易所接口测试 12 | * 13 | * @author lusongsong 14 | * @date 2020/11/20 15:15 15 | */ 16 | @SpringBootTest 17 | public class HKApiTests extends StockBaseTests { 18 | /** 19 | * 港股测试股票编码 20 | */ 21 | private static final String TEST_HK_STOCK_CODE = TEST_HK_STOCK.getStockCode(); 22 | /** 23 | * 港股接口 24 | */ 25 | @Autowired 26 | HKStockInfoApi hkStockInfoApi; 27 | @Autowired 28 | HKKLineApi hkkLineApi; 29 | 30 | 31 | /** 32 | * 按天成交信息测试 33 | */ 34 | @Test 35 | void stockInfoTest() { 36 | System.out.println(hkStockInfoApi.stockInfo( 37 | hkStockInfoApi.apiToken(), TEST_HK_STOCK_CODE 38 | )); 39 | } 40 | 41 | /** 42 | * K线数据测试 43 | */ 44 | @Test 45 | void kLineTest() { 46 | System.out.println(hkkLineApi.kLine( 47 | TEST_HK_STOCK, HKKLineApi.HK_KLINE_MINUTE, hkStockInfoApi.apiToken() 48 | )); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsDayDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 按天成交信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/6 13:54 13 | */ 14 | @Data 15 | public class NetsDayDealInfoPo implements Serializable { 16 | /** 17 | * 交易日期 18 | */ 19 | String dt; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName; 28 | /** 29 | * 收盘价 30 | */ 31 | BigDecimal closePrice; 32 | /** 33 | * 最高价 34 | */ 35 | BigDecimal highestPrice; 36 | /** 37 | * 最低价 38 | */ 39 | BigDecimal lowestPrice; 40 | /** 41 | * 开盘价 42 | */ 43 | BigDecimal openPrice; 44 | /** 45 | * 前收盘价 46 | */ 47 | BigDecimal preClosePrice; 48 | /** 49 | * 涨跌额 50 | */ 51 | BigDecimal uptickPrice; 52 | /** 53 | * 涨跌幅 54 | */ 55 | BigDecimal uptickRate; 56 | /** 57 | * 换手率 58 | */ 59 | BigDecimal turnoverRate; 60 | /** 61 | * 成交量 62 | */ 63 | Long dealNum; 64 | /** 65 | * 成交金额 66 | */ 67 | BigDecimal dealMoney; 68 | /** 69 | * 总市值 70 | */ 71 | BigDecimal totalValue; 72 | /** 73 | * 流通值 74 | */ 75 | BigDecimal circValue; 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/util/CharsetUtil.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.util; 2 | 3 | import java.io.UnsupportedEncodingException; 4 | 5 | /** 6 | * 字符串编码格式转换 7 | * 8 | * @author lusongsong 9 | * @date 2020/11/4 15:52 10 | */ 11 | public class CharsetUtil { 12 | 13 | /** 14 | * GBK转UTF-8 15 | * 16 | * @param gbkStr 17 | * @return 18 | */ 19 | public static String convertGBKToUtf8(String gbkStr) { 20 | try { 21 | int n = gbkStr.length(); 22 | byte[] utfBytes = new byte[3 * n]; 23 | int k = 0; 24 | for (int i = 0; i < n; i++) { 25 | int m = gbkStr.charAt(i); 26 | if (m < 128 && m >= 0) { 27 | utfBytes[k++] = (byte) m; 28 | continue; 29 | } 30 | utfBytes[k++] = (byte) (0xe0 | (m >> 12)); 31 | utfBytes[k++] = (byte) (0x80 | ((m >> 6) & 0x3f)); 32 | utfBytes[k++] = (byte) (0x80 | (m & 0x3f)); 33 | } 34 | if (k < utfBytes.length) { 35 | byte[] tmp = new byte[k]; 36 | System.arraycopy(utfBytes, 0, tmp, 0, k); 37 | return new String(tmp, "UTF-8"); 38 | } else { 39 | return new String(utfBytes, "UTF-8"); 40 | } 41 | } catch (UnsupportedEncodingException e) { 42 | throw new InternalError(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sz/SZStockInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sz; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | import java.math.BigDecimal; 8 | 9 | /** 10 | * 深市股票信息 11 | * 12 | * @author lusongsong 13 | * @date 2020/11/20 14:31 14 | */ 15 | @Data 16 | public class SZStockInfoPo implements Serializable { 17 | /** 18 | * 股票所属交易所 19 | */ 20 | Integer stockMarket = StockConst.SM_SZ; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode = ""; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName = ""; 29 | /** 30 | * 股票全称 31 | */ 32 | String stockFullName = ""; 33 | /** 34 | * 股票英文全称 35 | */ 36 | String stockFullNameEn = ""; 37 | /** 38 | * 股票公司注册地址 39 | */ 40 | String stockRegisterAddress = ""; 41 | /** 42 | * 股票公司官方网址 43 | */ 44 | String stockWebsite = ""; 45 | /** 46 | * 股票上市日期 47 | */ 48 | String stockOnDate = ""; 49 | /** 50 | * 股票总股本(万) 51 | */ 52 | BigDecimal stockTotalEquity = BigDecimal.ZERO; 53 | /** 54 | * 股票流通股本(万) 55 | */ 56 | BigDecimal stockCircEquity = BigDecimal.ZERO; 57 | /** 58 | * 股票公司所在地理位置区域 59 | */ 60 | String stockArea = ""; 61 | /** 62 | * 股票公司所在省份 63 | */ 64 | String stockProvince = ""; 65 | /** 66 | * 股票公司所在城市 67 | */ 68 | String stockCity = ""; 69 | /** 70 | * 股票所属行业 71 | */ 72 | String stockIndustry = ""; 73 | } 74 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/SZApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.sz.SZKLineApi; 5 | import com.fox.spider.stock.api.sz.SZRealtimeDealApi; 6 | import com.fox.spider.stock.api.sz.SZStockInfoApi; 7 | import com.fox.spider.stock.constant.StockConst; 8 | import org.junit.jupiter.api.Test; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.boot.test.context.SpringBootTest; 11 | 12 | /** 13 | * 深市交易所接口测试类 14 | * 15 | * @author lusongsong 16 | * @date 2020/11/20 14:38 17 | */ 18 | @SpringBootTest 19 | public class SZApiTests extends StockBaseTests { 20 | /** 21 | * 深市测试股票编码 22 | */ 23 | private static final String TEST_SZ_STOCK_CODE = TEST_SZ_STOCK.getStockCode(); 24 | /** 25 | * 深市接口 26 | */ 27 | @Autowired 28 | SZStockInfoApi szStockInfoApi; 29 | @Autowired 30 | SZRealtimeDealApi szRealtimeDealApi; 31 | @Autowired 32 | SZKLineApi szkLineApi; 33 | 34 | /** 35 | * 按天成交信息测试 36 | */ 37 | @Test 38 | void stockInfoTest() { 39 | System.out.println(szStockInfoApi.stockInfo(TEST_SZ_STOCK_CODE)); 40 | } 41 | 42 | /** 43 | * 深证股票最新交易日交易数据测试 44 | */ 45 | @Test 46 | void realtimeDealTest() { 47 | System.out.println(szRealtimeDealApi.realtimeDeal(TEST_SZ_STOCK)); 48 | } 49 | 50 | /** 51 | * 深证股票k线数据测试 52 | */ 53 | @Test 54 | void kLineTest() { 55 | System.out.println(szkLineApi.kline(TEST_SZ_STOCK, StockConst.DT_DAY)); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaBigDealSumPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | 8 | /** 9 | * 新浪网大额交易汇总信息 10 | * 11 | * @author lusongsong 12 | * @date 2021/1/11 14:20 13 | */ 14 | @Data 15 | public class SinaBigDealSumPo implements Serializable { 16 | /** 17 | * 股票所属交易所 18 | */ 19 | Integer stockMarket; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName; 28 | /** 29 | * 日期 30 | */ 31 | String dt; 32 | /** 33 | * 大单平均成交价 34 | */ 35 | BigDecimal avgPrice; 36 | /** 37 | * 成交股数 38 | */ 39 | Long dealNum; 40 | /** 41 | * 成交金额 42 | */ 43 | BigDecimal dealMoney; 44 | /** 45 | * 大单成交量 46 | */ 47 | Long bigDealNum; 48 | /** 49 | * 大单成交金额 50 | */ 51 | BigDecimal bigDealMoney; 52 | /** 53 | * 大单买入成交量 54 | */ 55 | Long bigBuyDealNum; 56 | /** 57 | * 大单买入成交金额 58 | */ 59 | BigDecimal bigBuyDealMoney; 60 | /** 61 | * 大单卖出成交量 62 | */ 63 | Long bigSellDealNum; 64 | /** 65 | * 大单卖出成交金额 66 | */ 67 | BigDecimal bigSellDealMoney; 68 | /** 69 | * 大单中性成交量 70 | */ 71 | Long bigFlatDealNum; 72 | /** 73 | * 大单中性成交金额 74 | */ 75 | BigDecimal bigFlatDealMoney; 76 | /** 77 | * 大单成交量占比 78 | */ 79 | BigDecimal bigDealNumRatio; 80 | /** 81 | * 大单成交金额占比 82 | */ 83 | BigDecimal bigDealMoneyRatio; 84 | } 85 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/SHApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.sh.SHRealtimeDealInfoApi; 5 | import com.fox.spider.stock.api.sh.SHRealtimeMinuteKLineApi; 6 | import com.fox.spider.stock.api.sh.SHStockInfoApi; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | /** 12 | * 沪市交易所接口测试类 13 | * 14 | * @author lusongsong 15 | * @date 2020/11/20 14:15 16 | */ 17 | @SpringBootTest 18 | public class SHApiTests extends StockBaseTests { 19 | /** 20 | * 沪市测试股票编码 21 | */ 22 | private static final String TEST_SH_STOCK_CODE = TEST_SH_STOCK.getStockCode(); 23 | /** 24 | * 沪市接口 25 | */ 26 | @Autowired 27 | SHStockInfoApi shStockInfoApi; 28 | @Autowired 29 | SHRealtimeMinuteKLineApi shRealtimeMinuteKLineApi; 30 | @Autowired 31 | SHRealtimeDealInfoApi shRealtimeDealInfoApi; 32 | 33 | /** 34 | * 按天成交信息测试 35 | */ 36 | @Test 37 | void stockInfoTest() { 38 | System.out.println(shStockInfoApi.stockInfo(TEST_SH_STOCK_CODE)); 39 | } 40 | 41 | /** 42 | * 最新交易日分钟新图数据测试 43 | */ 44 | @Test 45 | void realtimeMinuteKLineTest() { 46 | System.out.println(shRealtimeMinuteKLineApi.realtimeMinuteKLine(TEST_SH_STOCK)); 47 | } 48 | 49 | /** 50 | * 最新交易日交易详情信息 51 | */ 52 | @Test 53 | void realtimeDealInfoTest() { 54 | System.out.println(shRealtimeDealInfoApi.realtimeDealInfo(TEST_SH_STOCK)); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sh/SHStockInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sh; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import lombok.Data; 5 | 6 | import java.io.Serializable; 7 | 8 | /** 9 | * 沪市股票信息 10 | * 11 | * @author lusongsong 12 | * @date 2020/11/19 18:14 13 | */ 14 | @Data 15 | public class SHStockInfoPo implements Serializable { 16 | /** 17 | * 股票所属交易所 18 | */ 19 | Integer stockMarket = StockConst.SM_SH; 20 | /** 21 | * 股票代码 22 | */ 23 | String stockCode = ""; 24 | /** 25 | * 股票名称 26 | */ 27 | String stockName = ""; 28 | /** 29 | * 股票英文名称 30 | */ 31 | String stockNameEn = ""; 32 | /** 33 | * 股票全称 34 | */ 35 | String stockFullName = ""; 36 | /** 37 | * 股票英文全称 38 | */ 39 | String stockFullNameEn = ""; 40 | /** 41 | * 公司法人代表 42 | */ 43 | String stockLegal = ""; 44 | /** 45 | * 股票公司注册地址 46 | */ 47 | String stockRegisterAddress = ""; 48 | /** 49 | * 股票公司通讯地址 50 | */ 51 | String stockConnectAddress = ""; 52 | /** 53 | * 股票公司邮箱 54 | */ 55 | String stockEmail = ""; 56 | /** 57 | * 股票公司官方网址 58 | */ 59 | String stockWebsite = ""; 60 | /** 61 | * 股票上市日期 62 | */ 63 | String stockOnDate = ""; 64 | /** 65 | * 股票总股本(万) 66 | */ 67 | Double stockTotalEquity = 0.0; 68 | /** 69 | * 股票流通股本(万) 70 | */ 71 | Double stockCircEquity = 0.0; 72 | /** 73 | * 股票公司所在省份 74 | */ 75 | String stockProvince = ""; 76 | /** 77 | * 股票所属行业 78 | */ 79 | String stockIndustry = ""; 80 | /** 81 | * 股票CSRC行业(门类/大类/中类) 82 | */ 83 | String stockCarc = ""; 84 | } 85 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/nets/NetsRealtimeDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.nets; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.TreeMap; 8 | 9 | /** 10 | * 网易股票最新交易日交易数据 11 | * 12 | * @author lusongsong 13 | * @date 2021/1/18 17:51 14 | */ 15 | @Data 16 | public class NetsRealtimeDealInfoPo implements Serializable { 17 | /** 18 | * 股票交易所 19 | */ 20 | Integer stockMarket; 21 | /** 22 | * 股票代码 23 | */ 24 | String stockCode; 25 | /** 26 | * 股票名称 27 | */ 28 | String stockName; 29 | /** 30 | * 当前价格 31 | */ 32 | BigDecimal currentPrice; 33 | /** 34 | * 今日开盘价 35 | */ 36 | BigDecimal openPrice; 37 | /** 38 | * 今日最高价 39 | */ 40 | BigDecimal highestPrice; 41 | /** 42 | * 今日最低价 43 | */ 44 | BigDecimal lowestPrice; 45 | /** 46 | * 昨日收盘价 47 | */ 48 | BigDecimal preClosePrice; 49 | /** 50 | * 价格涨幅 51 | */ 52 | BigDecimal uptickPrice; 53 | /** 54 | * 增长率 55 | */ 56 | BigDecimal uptickRate; 57 | /** 58 | * 竞买价 59 | */ 60 | BigDecimal competeBuyPrice; 61 | /** 62 | * 竞卖价 63 | */ 64 | BigDecimal competeSellPrice; 65 | /** 66 | * 成交股数 67 | */ 68 | Long dealNum; 69 | /** 70 | * 成交金额 71 | */ 72 | BigDecimal dealMoney; 73 | /** 74 | * 排名靠前的5个买方报价 75 | */ 76 | TreeMap buyPriceMap; 77 | /** 78 | * 排名靠前的5个卖方报价 79 | */ 80 | TreeMap sellPriceMap; 81 | /** 82 | * 当前日期 83 | */ 84 | String dt; 85 | /** 86 | * 当前时间 87 | */ 88 | String time; 89 | } 90 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/ifeng/IFengRealtimeDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.ifeng; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.TreeMap; 8 | import java.util.List; 9 | 10 | /** 11 | * 凤凰网股票实时成交信息 12 | * 13 | * @author lusongsong 14 | * @date 2021/1/4 15:38 15 | */ 16 | @Data 17 | public class IFengRealtimeDealInfoPo implements Serializable { 18 | /** 19 | * 股票交易所 20 | */ 21 | Integer stockMarket; 22 | /** 23 | * 股票代码 24 | */ 25 | String stockCode; 26 | /** 27 | * 股票名称 28 | */ 29 | String stockName; 30 | /** 31 | * 当前日期 32 | */ 33 | String dt; 34 | /** 35 | * 当前时间 36 | */ 37 | String time; 38 | /** 39 | * 当前价格 40 | */ 41 | BigDecimal currentPrice; 42 | /** 43 | * 今日开盘价 44 | */ 45 | BigDecimal openPrice; 46 | /** 47 | * 均价 48 | */ 49 | BigDecimal avgPrice; 50 | /** 51 | * 今日最高价 52 | */ 53 | BigDecimal highestPrice; 54 | /** 55 | * 今日最低价 56 | */ 57 | BigDecimal lowestPrice; 58 | /** 59 | * 昨日收盘价 60 | */ 61 | BigDecimal preClosePrice; 62 | /** 63 | * 价格涨幅 64 | */ 65 | BigDecimal uptickPrice; 66 | /** 67 | * 增长率 68 | */ 69 | BigDecimal uptickRate; 70 | /** 71 | * 成交股数 72 | */ 73 | Long dealNum; 74 | /** 75 | * 成交金额 76 | */ 77 | BigDecimal dealMoney; 78 | /** 79 | * 排名靠前的5个买方报价 80 | */ 81 | TreeMap buyPriceMap; 82 | /** 83 | * 排名靠前的5个卖方报价 84 | */ 85 | TreeMap sellPriceMap; 86 | /** 87 | * 未知的数据列表 88 | */ 89 | List unknownKeyList; 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sz/SZRealtimeDealPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sz; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.TreeMap; 8 | import java.util.List; 9 | 10 | /** 11 | * 深证最新交易日交易信息 12 | * 13 | * @author lusongsong 14 | * @date 2021/1/12 15:27 15 | */ 16 | @Data 17 | public class SZRealtimeDealPo implements Serializable { 18 | /** 19 | * 股票代码 20 | */ 21 | String stockCode; 22 | /** 23 | * 股票所属交易所 24 | */ 25 | Integer stockMarket; 26 | /** 27 | * 股票名称 28 | */ 29 | String StockName; 30 | /** 31 | * 日期 32 | */ 33 | String dt; 34 | /** 35 | * 时间 36 | */ 37 | String time; 38 | /** 39 | * 当前价格 40 | */ 41 | BigDecimal currentPrice; 42 | /** 43 | * 今日开盘价 44 | */ 45 | BigDecimal openPrice; 46 | /** 47 | * 今日最高价 48 | */ 49 | BigDecimal highestPrice; 50 | /** 51 | * 今日最低价 52 | */ 53 | BigDecimal lowestPrice; 54 | /** 55 | * 昨日收盘价 56 | */ 57 | BigDecimal preClosePrice; 58 | /** 59 | * 价格涨幅 60 | */ 61 | BigDecimal uptickPrice; 62 | /** 63 | * 增长率 64 | */ 65 | BigDecimal uptickRate; 66 | /** 67 | * 成交量 68 | */ 69 | Long dealNum; 70 | /** 71 | * 成交金额 72 | */ 73 | BigDecimal dealMoney; 74 | /** 75 | * 排名靠前的5个买方报价 76 | */ 77 | TreeMap buyPriceMap; 78 | /** 79 | * 排名靠前的5个卖方报价 80 | */ 81 | TreeMap sellPriceMap; 82 | /** 83 | * 未知的数据列表 84 | */ 85 | List unknownKeyList; 86 | /** 87 | * 分钟线图数据 88 | */ 89 | List minuteKLine; 90 | } 91 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sh/SHRealtimeDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sh; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.List; 8 | import java.util.TreeMap; 9 | 10 | /** 11 | * 证股票最新交易数据 12 | * 13 | * @author lusongsong 14 | * @date 2021/1/12 11:25 15 | */ 16 | @Data 17 | public class SHRealtimeDealInfoPo implements Serializable { 18 | /** 19 | * 股票代码 20 | */ 21 | String stockCode; 22 | /** 23 | * 股票所属交易所 24 | */ 25 | Integer stockMarket; 26 | /** 27 | * 股票名称 28 | */ 29 | String StockName; 30 | /** 31 | * 日期 32 | */ 33 | String dt; 34 | /** 35 | * 时间 36 | */ 37 | String time; 38 | /** 39 | * 当前价格 40 | */ 41 | BigDecimal currentPrice; 42 | /** 43 | * 今日开盘价 44 | */ 45 | BigDecimal openPrice; 46 | /** 47 | * 今日最高价 48 | */ 49 | BigDecimal highestPrice; 50 | /** 51 | * 今日最低价 52 | */ 53 | BigDecimal lowestPrice; 54 | /** 55 | * 昨日收盘价 56 | */ 57 | BigDecimal preClosePrice; 58 | /** 59 | * 涨停价 60 | */ 61 | BigDecimal upLimitPrice; 62 | /** 63 | * 跌停价 64 | */ 65 | BigDecimal downLimitPrice; 66 | /** 67 | * 价格涨幅 68 | */ 69 | BigDecimal uptickPrice; 70 | /** 71 | * 增长率 72 | */ 73 | BigDecimal uptickRate; 74 | /** 75 | * 成交量 76 | */ 77 | Long dealNum; 78 | /** 79 | * 成交金额 80 | */ 81 | BigDecimal dealMoney; 82 | /** 83 | * 排名靠前的5个买方报价 84 | */ 85 | TreeMap buyPriceMap; 86 | /** 87 | * 排名靠前的5个卖方报价 88 | */ 89 | TreeMap sellPriceMap; 90 | /** 91 | * 未知的数据列表 92 | */ 93 | List unknownKeyList; 94 | } 95 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/dto/http/HttpResponseDto.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.dto.http; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import lombok.Data; 5 | import org.apache.commons.lang3.StringUtils; 6 | 7 | import java.io.IOException; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 接口响应返回类 13 | * 14 | * @author lusongsong 15 | * @date 2020/11/4 16:28 16 | */ 17 | @Data 18 | public class HttpResponseDto { 19 | /** 20 | * 错误码 21 | */ 22 | Integer code; 23 | /** 24 | * 错误信息 25 | */ 26 | String msg; 27 | /** 28 | * 请求响应头 29 | */ 30 | Map> headers; 31 | /** 32 | * 请求地址 33 | */ 34 | String requestUrl; 35 | /** 36 | * 接口返回 37 | */ 38 | String content; 39 | 40 | /** 41 | * 构造函数 42 | * 43 | * @param code 44 | * @param msg 45 | * @param headers 46 | * @param requestUrl 47 | * @param content 48 | */ 49 | public HttpResponseDto(int code, String msg, Map> headers, String requestUrl, String content) { 50 | this.code = code; 51 | this.msg = msg; 52 | this.headers = headers; 53 | this.requestUrl = requestUrl; 54 | this.content = content; 55 | } 56 | 57 | /** 58 | * 接口返回转对象 59 | * 60 | * @param clz 61 | * @param 62 | * @return 63 | * @throws IOException 64 | */ 65 | public T getContent(Class clz) throws IOException { 66 | if (StringUtils.isNotBlank(content)) { 67 | return JSONObject.parseObject(content, clz); 68 | } 69 | return null; 70 | } 71 | 72 | /** 73 | * 判断请求是否成功 74 | * 75 | * @return 76 | */ 77 | public boolean isSuccess() { 78 | return 200 == code; 79 | } 80 | 81 | /** 82 | * 判断请求是否失败 83 | * 84 | * @return 85 | */ 86 | public boolean isError() { 87 | return 200 != code; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/NetsApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.nets.*; 5 | import com.fox.spider.stock.constant.StockConst; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | /** 11 | * 网易接口测试类 12 | * 13 | * @author lusongsong 14 | * @date 2020/11/6 14:07 15 | */ 16 | @SpringBootTest 17 | class NetsApiTests extends StockBaseTests { 18 | /** 19 | * 网易接口 20 | */ 21 | @Autowired 22 | NetsDayDealInfoApi netsDayDealInfoApi; 23 | @Autowired 24 | NetsFQKLineDataApi netsFQKLineDataApi; 25 | @Autowired 26 | NetsRealtimeMinuteKLineApi netsRealtimeMinuteKLineApi; 27 | @Autowired 28 | NetsFQTotalClosePriceApi netsFQTotalClosePriceApi; 29 | @Autowired 30 | NetsRealtimeDealInfoApi netsRealtimeDealInfoApi; 31 | 32 | /** 33 | * 网易股票最新交易日交易数据接口测试 34 | */ 35 | @Test 36 | void realtimeDealInfoTest() { 37 | System.out.println(netsRealtimeDealInfoApi.realtimeDealInfo(TEST_SH_STOCK)); 38 | } 39 | 40 | /** 41 | * 按天成交信息测试 42 | */ 43 | @Test 44 | void dayDealInfoTest() { 45 | String startDate = "2020-10-01"; 46 | String endDate = "2020-11-01"; 47 | System.out.println(netsDayDealInfoApi.dayDealInfo(TEST_SH_STOCK, startDate, endDate)); 48 | } 49 | 50 | /** 51 | * 复权类型成交信息测试 52 | */ 53 | @Test 54 | void fqKLineDataTest() { 55 | String startDate = "2019-10-01"; 56 | String endDate = "2020-11-01"; 57 | System.out.println(netsFQKLineDataApi.fqKLineData(TEST_SH_STOCK, startDate, endDate, StockConst.SFQ_BEFORE)); 58 | } 59 | 60 | /** 61 | * 实时交易分钟线图数据测试 62 | */ 63 | @Test 64 | void realtimeMinuteKLineTest() { 65 | System.out.println(netsRealtimeMinuteKLineApi.realtimeMinuteKLine(TEST_SH_STOCK)); 66 | } 67 | 68 | /** 69 | * 实时交易分钟线图数据测试 70 | */ 71 | @Test 72 | void netsFQTotalClosePriceTest() { 73 | System.out.println(netsFQTotalClosePriceApi.fqClosePrice(TEST_SH_STOCK, StockConst.DT_DAY, StockConst.SFQ_BEFORE)); 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/util/BigDecimalUtil.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.util; 2 | 3 | import java.math.BigDecimal; 4 | import java.math.RoundingMode; 5 | 6 | /** 7 | * BigDecimal工具类 8 | * 9 | * @author lusongsong 10 | * @date 2020/11/4 17:05 11 | */ 12 | public class BigDecimalUtil { 13 | /** 14 | * long值格式处理 15 | */ 16 | public static final BigDecimal LONG_MULTIPLY_100 = new BigDecimal(100); 17 | /** 18 | * 价格格式处理 19 | */ 20 | public static final BigDecimal PRICE_MULTIPLY_10000 = new BigDecimal(10000); 21 | /** 22 | * 百分比格式 23 | */ 24 | public static final BigDecimal RATE_MULTIPLY_100 = new BigDecimal(100); 25 | 26 | /** 27 | * 获取long类对象 28 | * 29 | * @param longStr 30 | * @return 31 | */ 32 | public static Long initLong(String longStr) { 33 | return new BigDecimal(longStr).longValue(); 34 | } 35 | 36 | /** 37 | * 获取long类对象 38 | * 39 | * @param longStr 40 | * @param format 41 | * @return 42 | */ 43 | public static Long initLong(String longStr, BigDecimal format) { 44 | return new BigDecimal(longStr).multiply(format).longValue(); 45 | } 46 | 47 | /** 48 | * 获取价格BigDecimal类对象 49 | * 50 | * @param price 51 | * @return 52 | */ 53 | public static BigDecimal initPrice(String price) { 54 | return new BigDecimal(price).setScale(2, RoundingMode.HALF_UP); 55 | } 56 | 57 | /** 58 | * 获取价格BigDecimal类对象 59 | * 60 | * @param price 61 | * @param format 62 | * @return 63 | */ 64 | public static BigDecimal initPrice(String price, BigDecimal format) { 65 | return new BigDecimal(price).multiply(format).setScale(2, RoundingMode.HALF_UP); 66 | } 67 | 68 | /** 69 | * 获取百分比BigDecimal对象 70 | * 71 | * @param rate 72 | * @return 73 | */ 74 | public static BigDecimal initRate(String rate) { 75 | return new BigDecimal(rate).setScale(2, RoundingMode.HALF_UP); 76 | } 77 | 78 | /** 79 | * 获取百分比BigDecimal对象 80 | * 81 | * @param rate 82 | * @param format 83 | * @return 84 | */ 85 | public static BigDecimal initRate(String rate, BigDecimal format) { 86 | return new BigDecimal(rate).multiply(format).setScale(2, RoundingMode.HALF_UP); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.vo.StockVo; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * 凤凰网股票数据接口基类 11 | * 12 | * @author lusongsong 13 | * @date 2021/1/4 15:06 14 | */ 15 | public class IFengBaseApi { 16 | /** 17 | * 返回数据key 18 | */ 19 | public static final String RESPONSE_KEY_RECORD = "record"; 20 | /** 21 | * 凤凰网股市对应的拼音 22 | */ 23 | public static final Map IFENG_SM_PY_MAP = new HashMap() {{ 24 | put(StockConst.SM_SH, "sh");//沪 25 | put(StockConst.SM_SZ, "sz");//深 26 | put(StockConst.SM_HK, "hk");//港 27 | }}; 28 | 29 | /** 30 | * 获取股市对应的拼音 31 | * 32 | * @param stockMarket 33 | * @return 34 | */ 35 | public static String iFengStockMarketPY(Integer stockMarket) { 36 | return IFENG_SM_PY_MAP.containsKey(stockMarket) ? 37 | IFENG_SM_PY_MAP.get(stockMarket) : "sh"; 38 | } 39 | 40 | /** 41 | * 获取凤凰网股票代码 42 | * 43 | * @param stockVo 44 | * @return 45 | */ 46 | public static String iFengStockCode(StockVo stockVo) { 47 | if (null == stockVo || null == stockVo.getStockCode() || stockVo.getStockCode().isEmpty() 48 | || null == stockVo.getStockMarket() || !StockConst.SM_ALL.contains(stockVo.getStockMarket())) { 49 | return null; 50 | } 51 | StringBuffer stringBuffer = new StringBuffer(); 52 | stringBuffer.append(iFengStockMarketPY(stockVo.getStockMarket())); 53 | stringBuffer.append(stockVo.getStockCode()); 54 | return stringBuffer.toString(); 55 | } 56 | 57 | /** 58 | * 获取股票信息 59 | * 60 | * @param iFengStockCode 61 | * @return 62 | */ 63 | public static StockVo iFengStockCodeToStockVo(String iFengStockCode) { 64 | if (null == iFengStockCode || iFengStockCode.isEmpty()) { 65 | return null; 66 | } 67 | for (Integer stockMarket : IFENG_SM_PY_MAP.keySet()) { 68 | String stockMarketPY = IFENG_SM_PY_MAP.get(stockMarket); 69 | if (iFengStockCode.startsWith(stockMarketPY)) { 70 | String stockCode = iFengStockCode.replace(stockMarketPY, ""); 71 | return new StockVo(stockCode, stockMarket); 72 | } 73 | } 74 | return null; 75 | } 76 | 77 | /** 78 | * 是否支持该证券所 79 | * 80 | * @param stockMarket 81 | * @return 82 | */ 83 | public static boolean isSupport(int stockMarket) { 84 | return IFENG_SM_PY_MAP.containsKey(stockMarket); 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/IFengApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.ifeng.*; 5 | import com.fox.spider.stock.constant.StockConst; 6 | import org.junit.jupiter.api.Test; 7 | import org.springframework.beans.factory.annotation.Autowired; 8 | import org.springframework.boot.test.context.SpringBootTest; 9 | 10 | import java.util.Arrays; 11 | 12 | /** 13 | * 凤凰网股票接口测试类 14 | * 15 | * @author lusongsong 16 | * @date 2021/1/4 16:17 17 | */ 18 | @SpringBootTest 19 | public class IFengApiTests extends StockBaseTests { 20 | /** 21 | * 凤凰网接口 22 | */ 23 | @Autowired 24 | IFengRealtimeDealInfoApi iFengRealtimeDealInfoApi; 25 | @Autowired 26 | IFengFiveDayMinuteKLineApi iFengFiveDayMinuteKLineApi; 27 | @Autowired 28 | IFengFiveDayMinuteScopeKLineApi iFengFiveDayMinuteScopeKLineApi; 29 | @Autowired 30 | IFengKLineApi iFengKLineApi; 31 | @Autowired 32 | IFengRealtimeBigDealApi iFengRealtimeBigDealApi; 33 | @Autowired 34 | IFengRealtimeDealDetailApi iFengRealtimeDealDetailApi; 35 | @Autowired 36 | IFengRealtimePriceDealNumApi iFengRealtimePriceDealNumApi; 37 | 38 | /** 39 | * 交易日成交信息测试 40 | */ 41 | @Test 42 | void batchRealtimeDealInfoTest() { 43 | System.out.println( 44 | iFengRealtimeDealInfoApi.batchRealtimeDealInfo( 45 | Arrays.asList(TEST_HK_STOCK) 46 | ) 47 | ); 48 | } 49 | 50 | /** 51 | * 5日分钟线图测试 52 | */ 53 | @Test 54 | void fiveDayKLineTest() { 55 | System.out.println( 56 | iFengFiveDayMinuteKLineApi.fiveDayKLine(TEST_SH_STOCK) 57 | ); 58 | } 59 | 60 | /** 61 | * 不同分钟粒度线图测试 62 | */ 63 | @Test 64 | void minuteScopeKLineTest() { 65 | System.out.println( 66 | iFengFiveDayMinuteScopeKLineApi.minuteScopeKLine(TEST_SH_STOCK, 15) 67 | ); 68 | } 69 | 70 | /** 71 | * 不同分钟粒度线图测试 72 | */ 73 | @Test 74 | void kLineTest() { 75 | System.out.println( 76 | iFengKLineApi.kLine(TEST_SH_STOCK, StockConst.DT_MONTH) 77 | ); 78 | } 79 | 80 | /** 81 | * 大单交易测试 82 | */ 83 | @Test 84 | void bigDealTest() { 85 | System.out.println( 86 | iFengRealtimeBigDealApi.bigDeal(TEST_SH_STOCK) 87 | ); 88 | } 89 | 90 | /** 91 | * 交易明细测试 92 | */ 93 | @Test 94 | void dealDetailTest() { 95 | System.out.println( 96 | iFengRealtimeDealDetailApi.dealDetail(TEST_SH_STOCK) 97 | ); 98 | } 99 | 100 | /** 101 | * 价格成交量测试 102 | */ 103 | @Test 104 | void priceDealNumTest() { 105 | System.out.println( 106 | iFengRealtimePriceDealNumApi.priceDealNum(TEST_SH_STOCK) 107 | ); 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.3.5.RELEASE 9 | 10 | 11 | com.fox.spider 12 | stock 13 | 0.0.1-SNAPSHOT 14 | stock 15 | stock spider api 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-test 29 | test 30 | 31 | 32 | org.junit.vintage 33 | junit-vintage-engine 34 | 35 | 36 | 37 | 38 | 39 | org.projectlombok 40 | lombok 41 | 42 | 43 | 44 | org.apache.commons 45 | commons-lang3 46 | 47 | 48 | 49 | com.alibaba 50 | fastjson 51 | 1.2.75 52 | 53 | 54 | 55 | org.jsoup 56 | jsoup 57 | 1.13.1 58 | 59 | 60 | 61 | 62 | spiderStock 63 | 64 | 65 | org.springframework.boot 66 | spring-boot-maven-plugin 67 | 68 | exec 69 | 70 | 71 | 72 | maven-surefire-plugin 73 | 74 | true 75 | 76 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 5 | import com.fox.spider.stock.entity.vo.StockVo; 6 | 7 | import java.util.Arrays; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * 新浪股票数据接口基类 14 | * 15 | * @author lusongsong 16 | * @date 2020/11/4 15:40 17 | */ 18 | public class SinaBaseApi { 19 | /** 20 | * 股票交易所对应的拼音 21 | */ 22 | public static Map SINA_SM_PY_MAP = new HashMap() {{ 23 | put(StockConst.SM_SH, "sh");//沪 24 | put(StockConst.SM_SZ, "sz");//深 25 | put(StockConst.SM_HK, "hk");//港 26 | }}; 27 | 28 | /** 29 | * 当日无交易的状态 30 | */ 31 | public static final List NO_DEAL_STATUS_LIST = Arrays.asList( 32 | "-3", 33 | "03", 34 | //新股未上市 35 | "-2", 36 | "07" 37 | ); 38 | 39 | /** 40 | * 处理json字符串的key无双引号的问题 41 | * 42 | * @param jsonStr 43 | * @return 44 | */ 45 | protected String handleJsonStr(String jsonStr) { 46 | return jsonStr.replaceAll("([a-zA-Z0-9_]+):", "\"$1\":"); 47 | } 48 | 49 | /** 50 | * 获取股票集市对应的拼音 51 | * 52 | * @param stockMarket 53 | * @return 54 | */ 55 | public static String sinaStockMarketPY(Integer stockMarket) { 56 | return SinaBaseApi.SINA_SM_PY_MAP.containsKey(stockMarket) ? 57 | SinaBaseApi.SINA_SM_PY_MAP.get(stockMarket) : "hs"; 58 | } 59 | 60 | /** 61 | * 获取新浪股票代码 62 | * 63 | * @param stockVo 64 | * @return 65 | */ 66 | public static String sinaStockCode(StockVo stockVo) { 67 | if (null == stockVo || null == stockVo.getStockCode() || stockVo.getStockCode().isEmpty() 68 | || null == stockVo.getStockMarket() || !StockConst.SM_ALL.contains(stockVo.getStockMarket())) { 69 | return null; 70 | } 71 | StringBuffer stringBuffer = new StringBuffer(); 72 | stringBuffer.append(SinaBaseApi.sinaStockMarketPY(stockVo.getStockMarket())); 73 | stringBuffer.append(stockVo.getStockCode()); 74 | return stringBuffer.toString(); 75 | } 76 | 77 | /** 78 | * 判断是够已被拒绝 79 | * 80 | * @param httpResponseDto 81 | * @return 82 | */ 83 | public static Boolean isForbidden(HttpResponseDto httpResponseDto) { 84 | return 456 == httpResponseDto.getCode(); 85 | } 86 | 87 | /** 88 | * 处理拒绝 89 | */ 90 | public static void handleForbidden() { 91 | try { 92 | Thread.sleep(300000); 93 | } catch (InterruptedException e) { 94 | } 95 | } 96 | 97 | /** 98 | * 是否支持该证券所 99 | * 100 | * @param stockMarket 101 | * @return 102 | */ 103 | public static boolean isSupport(int stockMarket) { 104 | return SINA_SM_PY_MAP.containsKey(stockMarket); 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/tencent/TencentRealtimeDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.tencent; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.util.TreeMap; 8 | import java.util.List; 9 | 10 | /** 11 | * 腾讯股票实时成交信息 12 | * 13 | * @author lusongsong 14 | * @date 2020/12/24 14:17 15 | */ 16 | @Data 17 | public class TencentRealtimeDealInfoPo implements Serializable { 18 | /** 19 | * 股票交易所 20 | */ 21 | Integer stockMarket; 22 | /** 23 | * 股票代码 24 | */ 25 | String stockCode; 26 | /** 27 | * 当前日期 28 | */ 29 | String dt; 30 | /** 31 | * 当前时间 32 | */ 33 | String time; 34 | /** 35 | * 股票名称 36 | */ 37 | String stockName; 38 | /** 39 | * 股票英文名 40 | */ 41 | String stockNameEn; 42 | /** 43 | * 当前价格 44 | */ 45 | BigDecimal currentPrice; 46 | /** 47 | * 今日开盘价 48 | */ 49 | BigDecimal openPrice; 50 | /** 51 | * 均价 52 | */ 53 | BigDecimal avgPrice; 54 | /** 55 | * 今日最高价 56 | */ 57 | BigDecimal highestPrice; 58 | /** 59 | * 今日最低价 60 | */ 61 | BigDecimal lowestPrice; 62 | /** 63 | * 昨日收盘价 64 | */ 65 | BigDecimal preClosePrice; 66 | /** 67 | * 涨停价 68 | */ 69 | BigDecimal upLimitPrice; 70 | /** 71 | * 跌停价 72 | */ 73 | BigDecimal downLimitPrice; 74 | /** 75 | * 价格涨幅 76 | */ 77 | BigDecimal uptickPrice; 78 | /** 79 | * 增长率 80 | */ 81 | BigDecimal uptickRate; 82 | /** 83 | * 振幅 84 | */ 85 | BigDecimal surgeRate; 86 | /** 87 | * 成交股数 88 | */ 89 | Long dealNum; 90 | /** 91 | * 成交金额 92 | */ 93 | BigDecimal dealMoney; 94 | /** 95 | * 盘后成交股数 96 | */ 97 | Long closeDealNum; 98 | /** 99 | * 盘后成交金额 100 | */ 101 | BigDecimal closeDealMoney; 102 | /** 103 | * 排名靠前的5个买方报价 104 | */ 105 | TreeMap buyPriceMap; 106 | /** 107 | * 排名靠前的5个卖方报价 108 | */ 109 | TreeMap sellPriceMap; 110 | /** 111 | * 总市值 112 | */ 113 | BigDecimal totalValue; 114 | /** 115 | * 流通值 116 | */ 117 | BigDecimal circValue; 118 | /** 119 | * 换手率 120 | */ 121 | BigDecimal turnoverRate; 122 | /** 123 | * 市净率 124 | */ 125 | BigDecimal pbrRate; 126 | /** 127 | * 市盈率(TTM) 128 | */ 129 | BigDecimal perRate; 130 | /** 131 | * 市盈率(动) 132 | */ 133 | BigDecimal perDynamicRate; 134 | /** 135 | * 市盈率(静) 136 | */ 137 | BigDecimal perStaticRate; 138 | /** 139 | * 量比 140 | */ 141 | BigDecimal qrrRate; 142 | /** 143 | * 委差 144 | */ 145 | Long committeeSent; 146 | /** 147 | * 52周最高价 148 | */ 149 | BigDecimal fiftyTwoWeekHighestPrice; 150 | /** 151 | * 51周最低阶 152 | */ 153 | BigDecimal fiftyTwoWeekLowestPrice; 154 | /** 155 | * 未知的数据列表 156 | */ 157 | List unknownKeyList; 158 | } 159 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/entity/po/sina/SinaRealtimeDealInfoPo.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.entity.po.sina; 2 | 3 | import lombok.Data; 4 | 5 | import java.io.Serializable; 6 | import java.math.BigDecimal; 7 | import java.math.RoundingMode; 8 | import java.util.TreeMap; 9 | import java.util.List; 10 | 11 | /** 12 | * 股票实时成交信息 13 | * 14 | * @author lusongsong 15 | * @date 2020/11/5 14:33 16 | */ 17 | @Data 18 | public class SinaRealtimeDealInfoPo implements Serializable { 19 | /** 20 | * 股票交易所 21 | */ 22 | Integer stockMarket; 23 | /** 24 | * 股票代码 25 | */ 26 | String stockCode; 27 | /** 28 | * 股票名称 29 | */ 30 | String stockName; 31 | /** 32 | * 股票英文名 33 | */ 34 | String stockNameEn; 35 | /** 36 | * 当前价格 37 | */ 38 | BigDecimal currentPrice; 39 | /** 40 | * 今日开盘价 41 | */ 42 | BigDecimal openPrice; 43 | /** 44 | * 今日最高价 45 | */ 46 | BigDecimal highestPrice; 47 | /** 48 | * 今日最低价 49 | */ 50 | BigDecimal lowestPrice; 51 | /** 52 | * 昨日收盘价 53 | */ 54 | BigDecimal preClosePrice; 55 | /** 56 | * 价格涨幅 57 | */ 58 | BigDecimal uptickPrice; 59 | /** 60 | * 增长率 61 | */ 62 | BigDecimal uptickRate; 63 | /** 64 | * 竞买价 65 | */ 66 | BigDecimal competeBuyPrice; 67 | /** 68 | * 竞卖价 69 | */ 70 | BigDecimal competeSellPrice; 71 | /** 72 | * 当前分钟最高价 73 | */ 74 | BigDecimal minuteHighestPrice; 75 | /** 76 | * 当前分钟最低价 77 | */ 78 | BigDecimal minuteLowestPrice; 79 | /** 80 | * 成交股数 81 | */ 82 | Long dealNum; 83 | /** 84 | * 成交金额 85 | */ 86 | BigDecimal dealMoney; 87 | /** 88 | * 排名靠前的5个买方报价 89 | */ 90 | TreeMap buyPriceMap; 91 | /** 92 | * 排名靠前的5个卖方报价 93 | */ 94 | TreeMap sellPriceMap; 95 | /** 96 | * 当前日期 97 | */ 98 | String dt; 99 | /** 100 | * 当前时间 101 | */ 102 | String time; 103 | /** 104 | * 交易状态 105 | */ 106 | String dealStatus; 107 | /** 108 | * 52周最高价 109 | */ 110 | BigDecimal fiftyTwoWeekHighestPrice; 111 | /** 112 | * 51周最低阶 113 | */ 114 | BigDecimal fiftyTwoWeekLowestPrice; 115 | /** 116 | * 股息率 117 | */ 118 | BigDecimal dividendYield; 119 | /** 120 | * 未知的数据列表 121 | */ 122 | List unknownKeyList; 123 | 124 | /** 125 | * 获取波动 126 | * 127 | * @return 128 | */ 129 | public BigDecimal getSurgeRate() { 130 | if (null == preClosePrice || null == highestPrice || null == lowestPrice 131 | || 0 == preClosePrice.compareTo(BigDecimal.ZERO) 132 | || 0 == highestPrice.compareTo(BigDecimal.ZERO) 133 | || 0 == lowestPrice.compareTo(BigDecimal.ZERO) 134 | ) { 135 | return BigDecimal.ZERO; 136 | } 137 | //波动 138 | BigDecimal surgeRate = highestPrice.subtract(lowestPrice) 139 | .multiply(new BigDecimal(100)) 140 | .divide(preClosePrice, 4, RoundingMode.HALF_UP); 141 | return surgeRate; 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/nets/NetsBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.nets; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.vo.StockVo; 5 | 6 | import java.util.Arrays; 7 | import java.util.HashMap; 8 | import java.util.List; 9 | import java.util.Map; 10 | 11 | /** 12 | * 网易股票数据接口基类 13 | * 14 | * @author lusongsong 15 | * @date 2020/11/5 16:47 16 | */ 17 | public class NetsBaseApi { 18 | /** 19 | * 股市对应的拼音 20 | */ 21 | public static final Map NETS_SM_PY_MAP = new HashMap() {{ 22 | put(StockConst.SM_SH, "hs");//沪 23 | put(StockConst.SM_SZ, "hs");//深 24 | }}; 25 | /** 26 | * 股票id对应的前缀 27 | */ 28 | public static final Map NETS_SM_PRE_CODE_MAP = new HashMap() {{ 29 | put(StockConst.SM_SH, "0");//沪 30 | put(StockConst.SM_SZ, "1");//深 31 | }}; 32 | 33 | /** 34 | * 获取股票集市对应的拼音 35 | * 36 | * @param stockMarket 37 | * @return 38 | */ 39 | public static String netsStockMarketPY(Integer stockMarket) { 40 | return NetsBaseApi.NETS_SM_PY_MAP.containsKey(stockMarket) ? 41 | NetsBaseApi.NETS_SM_PY_MAP.get(stockMarket) : ""; 42 | } 43 | 44 | /** 45 | * 获取股票编码对应的前缀 46 | * 47 | * @param stockMarket 48 | * @return 49 | */ 50 | protected static String netsStockPreCode(Integer stockMarket) { 51 | return NetsBaseApi.NETS_SM_PRE_CODE_MAP.containsKey(stockMarket) ? 52 | NetsBaseApi.NETS_SM_PRE_CODE_MAP.get(stockMarket) : ""; 53 | } 54 | 55 | /** 56 | * 获取网易对应的股票编码 57 | * 58 | * @param stockVo 59 | * @return 60 | */ 61 | public static String netsStockCode(StockVo stockVo) { 62 | if (null == stockVo || null == stockVo.getStockCode() || stockVo.getStockCode().isEmpty() 63 | || null == stockVo.getStockMarket()) { 64 | return null; 65 | } 66 | StringBuffer stringBuffer = new StringBuffer(); 67 | stringBuffer.append(NetsBaseApi.netsStockPreCode(stockVo.getStockMarket())); 68 | stringBuffer.append(stockVo.getStockCode()); 69 | return stringBuffer.toString(); 70 | } 71 | 72 | /** 73 | * 获取股票信息 74 | * 75 | * @param netsStockCode 76 | * @return 77 | */ 78 | public static StockVo netsStockCodeToStockVo(String netsStockCode) { 79 | if (null == netsStockCode || netsStockCode.isEmpty()) { 80 | return null; 81 | } 82 | for (Integer stockMarket : NETS_SM_PRE_CODE_MAP.keySet()) { 83 | String stockMarketPreCode = NETS_SM_PRE_CODE_MAP.get(stockMarket); 84 | if (netsStockCode.startsWith(stockMarketPreCode)) { 85 | String stockCode = netsStockCode.replaceFirst(stockMarketPreCode, ""); 86 | return new StockVo(stockCode, stockMarket); 87 | } 88 | } 89 | return null; 90 | } 91 | 92 | /** 93 | * 是否支持该证券所 94 | * 95 | * @param stockMarket 96 | * @return 97 | */ 98 | public static boolean isSupport(int stockMarket) { 99 | return NETS_SM_PRE_CODE_MAP.containsKey(stockMarket); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/service/impl/StockToolImpl.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.service.impl; 2 | 3 | import com.fox.spider.stock.api.sina.SinaRealtimeDealInfoApi; 4 | import com.fox.spider.stock.constant.StockConst; 5 | import com.fox.spider.stock.entity.po.sina.SinaRealtimeDealInfoPo; 6 | import com.fox.spider.stock.entity.vo.StockCategoryVo; 7 | import com.fox.spider.stock.entity.vo.StockVo; 8 | import com.fox.spider.stock.service.StockToolService; 9 | import org.springframework.stereotype.Service; 10 | 11 | import java.math.BigDecimal; 12 | import java.math.RoundingMode; 13 | 14 | /** 15 | * 股票工具服务实现 16 | * 17 | * @author lusongsong 18 | * @date 2020/11/24 13:40 19 | */ 20 | @Service 21 | public class StockToolImpl implements StockToolService { 22 | /** 23 | * 获取最新交易日 24 | * 25 | * @param stockMarket 26 | * @return 27 | */ 28 | @Override 29 | public String lastDealDate(Integer stockMarket) { 30 | SinaRealtimeDealInfoApi sinaRealtimeDealInfoApi = new SinaRealtimeDealInfoApi(); 31 | if (StockConst.DEMO_STOCK.containsKey(stockMarket)) { 32 | StockVo stockVo = StockConst.DEMO_STOCK.get(stockMarket); 33 | if (null != stockVo) { 34 | SinaRealtimeDealInfoPo sinaRealtimeDealInfoPo = sinaRealtimeDealInfoApi.realtimeDealInfo(stockVo); 35 | if (null != sinaRealtimeDealInfoPo && null != sinaRealtimeDealInfoPo.getDt()) { 36 | return sinaRealtimeDealInfoPo.getDt(); 37 | } 38 | } 39 | } 40 | return ""; 41 | } 42 | 43 | /** 44 | * 获取涨跌幅限制 45 | * 46 | * @param stockVo 47 | * @param stockName 48 | * @return 49 | */ 50 | @Override 51 | public BigDecimal limitRate(StockVo stockVo, String stockName) { 52 | if (null == stockVo) { 53 | return null; 54 | } 55 | 56 | Integer stockMarket = stockVo.getStockMarket(); 57 | String stockCode = stockVo.getStockCode(); 58 | 59 | //无涨跌幅限制的交易所 60 | if (StockConst.SM_NO_LIMIT_LIST.contains(stockMarket)) { 61 | return null; 62 | } 63 | 64 | //A股处理 65 | if (StockConst.SM_A_LIST.contains(stockMarket)) { 66 | if (null == stockCode || stockCode.isEmpty()) { 67 | return null; 68 | } 69 | StockCategoryVo stockCategoryVo = StockConst.stockCategory(stockCode, stockMarket); 70 | if (null == stockCategoryVo) { 71 | return null; 72 | } 73 | //科创板,创业版涨跌幅限制为20% 74 | if (StockConst.SK_SZ_STOCK_GEM == stockCategoryVo.getStockKind() 75 | || StockConst.SK_SH_STOCK_STAR == stockCategoryVo.getStockKind()) { 76 | //科创板,创业版新股上市(前5日)无涨跌幅限制 77 | if (null != stockName && !stockName.isEmpty()) { 78 | if (stockName.startsWith(StockConst.STOCK_NAME_NEW) 79 | || stockName.startsWith(StockConst.STOCK_NAME_C)) { 80 | return null; 81 | } 82 | } 83 | 84 | return new BigDecimal(0.2).setScale(2, RoundingMode.HALF_UP); 85 | } 86 | //非ST的股票涨跌幅限制为10%,ST的股票涨跌幅限制为5% 87 | double limitRate = null != stockName && stockName.contains(StockConst.STOCK_NAME_ST) ? 0.05 : 0.1; 88 | return new BigDecimal(limitRate).setScale(2, RoundingMode.HALF_UP); 89 | } 90 | return null; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/tencent/TencentRelateBlockApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.tencent; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.tencent.TencentRelateBlockPo; 8 | import com.fox.spider.stock.entity.po.tencent.TencentRelateStockPo; 9 | import com.fox.spider.stock.entity.vo.StockVo; 10 | import com.fox.spider.stock.util.HttpUtil; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.HashMap; 18 | import java.util.List; 19 | import java.util.Map; 20 | 21 | /** 22 | * 滕讯股票所属板块接口 23 | * 24 | * @author lusongsong 25 | * @date 2020/12/29 18:15 26 | */ 27 | @Component 28 | public class TencentRelateBlockApi extends TencentBaseApi { 29 | /** 30 | * 日志 31 | */ 32 | private Logger logger = LoggerFactory.getLogger(getClass()); 33 | /** 34 | * 接口地址 35 | * https://proxy.finance.qq.com/ifzqgtimg/stock/relate/data/plate?code=sz000002 36 | */ 37 | private static final String API_URL = "https://proxy.finance.qq.com/ifzqgtimg/stock/relate/data/plate"; 38 | 39 | /** 40 | * 获取股票所属板块 41 | * 42 | * @param stockVo 43 | * @return 44 | */ 45 | public List relateBlock(StockVo stockVo) { 46 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 47 | return null; 48 | } 49 | try { 50 | String tencnetStockCode = TencentBaseApi.tencentStockCode(stockVo); 51 | Map params = new HashMap<>(1); 52 | params.put("code", tencnetStockCode); 53 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 54 | .setParams(params) 55 | .setOriCharset(HttpUtil.CHARSET_GBK) 56 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 57 | HttpResponseDto httpResponse = httpUtil.request(); 58 | List tencentRelateBlockPoList = handleResponse(httpResponse.getContent()); 59 | return tencentRelateBlockPoList; 60 | } catch (IOException e) { 61 | logger.error(stockVo.toString(), e); 62 | } 63 | return null; 64 | } 65 | 66 | /** 67 | * 解析返回数据 68 | * 69 | * @param response 70 | * @return 71 | */ 72 | private List handleResponse(String response) { 73 | if (null == response || response.isEmpty()) { 74 | return null; 75 | } 76 | try { 77 | JSONObject jsonObject = JSONObject.parseObject(response); 78 | if (null == jsonObject || !jsonObject.containsKey(RESPONSE_KEY_DATA)) { 79 | return null; 80 | } 81 | JSONArray jsonArray = jsonObject.getJSONArray(RESPONSE_KEY_DATA); 82 | if (null == jsonArray || jsonArray.isEmpty()) { 83 | return null; 84 | } 85 | List tencentRelateBlockPoList = new ArrayList<>(); 86 | for (int i = 0; i < jsonArray.size(); i++) { 87 | JSONObject relateJSONObject = jsonArray.getJSONObject(i); 88 | if (!relateJSONObject.containsKey(RESPONSE_KEY_CODE) || !relateJSONObject.containsKey(RESPONSE_KEY_NAME)) { 89 | continue; 90 | } 91 | TencentRelateBlockPo tencentRelateBlockPo = new TencentRelateBlockPo(); 92 | tencentRelateBlockPo.setCode(relateJSONObject.getString(RESPONSE_KEY_CODE)); 93 | tencentRelateBlockPo.setName(relateJSONObject.getString(RESPONSE_KEY_NAME)); 94 | tencentRelateBlockPoList.add(tencentRelateBlockPo); 95 | } 96 | return tencentRelateBlockPoList; 97 | } catch (JSONException e) { 98 | logger.error(response, e); 99 | } 100 | return null; 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaFQPriceLineApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.fox.spider.stock.constant.StockConst; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.vo.StockVo; 8 | import com.fox.spider.stock.util.BigDecimalUtil; 9 | import com.fox.spider.stock.util.HttpUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.io.IOException; 15 | import java.math.BigDecimal; 16 | import java.util.*; 17 | 18 | /** 19 | * 股票不同复权类型价格线 20 | * 不支持港股 21 | * 22 | * @author lusongsong 23 | * @date 2020/11/5 15:17 24 | */ 25 | @Component 26 | public class SinaFQPriceLineApi extends SinaBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 样例链接 33 | * http://finance.sina.com.cn/realstock/company/sh603383/qianfuquan.js 34 | */ 35 | /** 36 | * 接口 37 | */ 38 | private static String apiUrl = "http://finance.sina.com.cn/realstock/company/{stockCode}/{rehabilitationType}.js"; 39 | /** 40 | * 复权类型 41 | */ 42 | private static Map fqTypeMap = new HashMap() {{ 43 | put(StockConst.SFQ_BEFORE, "qianfuquan");//前复权 44 | put(StockConst.SFQ_AFTER, "houfuquan");//后复权 45 | }}; 46 | 47 | /** 48 | * 获取复权价格信息 49 | * 50 | * @param stockVo 51 | * @param fqType 52 | * @return 53 | */ 54 | public Map fqPriceLine(StockVo stockVo, Integer fqType) { 55 | Map map = new HashMap<>(0); 56 | try { 57 | if (!fqTypeMap.containsKey(fqType)) { 58 | return map; 59 | } 60 | String url = apiUrl.replace("{stockCode}", SinaBaseApi.sinaStockCode(stockVo)) 61 | .replace("{rehabilitationType}", fqTypeMap.get(fqType)); 62 | HttpUtil httpUtil = new HttpUtil(); 63 | httpUtil.setUrl(url) 64 | .setOriCharset(HttpUtil.CHARSET_GBK) 65 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 66 | HttpResponseDto httpResponse = httpUtil.request(); 67 | return this.handleResponse(httpResponse.getContent()); 68 | } catch (IOException e) { 69 | logger.error(e.getMessage()); 70 | } 71 | return map; 72 | } 73 | 74 | /** 75 | * 处理返回信息 76 | * 77 | * @param response 78 | * @return 79 | */ 80 | private Map handleResponse(String response) { 81 | //去掉返回数据中的注释信息 82 | response = this.clearAnnotation(response); 83 | //给json字符串的key加双引号 84 | response = this.handleJsonStr(response); 85 | try { 86 | JSONArray jsonArray = JSONArray.parseArray(response); 87 | JSONObject jsonObject = (JSONObject) jsonArray.get(0); 88 | JSONObject dataObject = (JSONObject) jsonObject.get("data"); 89 | Set dataKeySet = dataObject.keySet(); 90 | Map map = new TreeMap<>(); 91 | for (String key : dataKeySet) { 92 | BigDecimal value = BigDecimalUtil.initPrice(dataObject.getString(key)); 93 | if (key.startsWith("_")) { 94 | key = key.substring(1); 95 | } 96 | key = key.replace("_", "-"); 97 | map.put(key, value); 98 | } 99 | return map; 100 | } catch (Exception e) { 101 | logger.error(response); 102 | logger.error(e.getMessage()); 103 | } 104 | return new HashMap<>(0); 105 | } 106 | 107 | /** 108 | * 去掉返回数据中的注释信息 109 | * 110 | * @param response 111 | * @return 112 | */ 113 | private String clearAnnotation(String response) { 114 | int annotationIndex = response.lastIndexOf("/*"); 115 | return -1 == annotationIndex ? response : response.substring(0, annotationIndex); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaPriceDealNumRatioApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 4 | import com.fox.spider.stock.entity.po.sina.SinaPriceDealNumRatioPo; 5 | import com.fox.spider.stock.entity.vo.StockVo; 6 | import com.fox.spider.stock.util.BigDecimalUtil; 7 | import com.fox.spider.stock.util.HttpUtil; 8 | import org.slf4j.Logger; 9 | import org.slf4j.LoggerFactory; 10 | import org.springframework.stereotype.Component; 11 | 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.List; 15 | import java.util.regex.Matcher; 16 | import java.util.regex.Pattern; 17 | 18 | /** 19 | * 股票成交价格占比 20 | * 只能情请求截止至上个交易日的数据,不能高频次访问,会被拦截 21 | * 22 | * @author lusongsong 23 | * @date 2020/11/5 14:08 24 | */ 25 | @Component 26 | public class SinaPriceDealNumRatioApi extends SinaBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 样例链接 33 | * http://market.finance.sina.com.cn/iframe/pricehis.php?symbol=sh603383&startdate=2019-12-01&enddate=2019-12-13 34 | */ 35 | /** 36 | * 接口 37 | */ 38 | private static String apiUrl = "http://market.finance.sina.com.cn/iframe/pricehis.php"; 39 | 40 | /** 41 | * 股票成交价格占比 42 | * 不支持港股 43 | * 44 | * @param stockVo 45 | * @param startDate 46 | * @param endDate 47 | * @return 48 | */ 49 | public List priceDealNumRatio(StockVo stockVo, String startDate, String endDate) { 50 | List list = new ArrayList<>(); 51 | try { 52 | HttpUtil httpUtil = new HttpUtil(); 53 | httpUtil.setUrl(apiUrl) 54 | .setOriCharset(HttpUtil.CHARSET_GBK) 55 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 56 | httpUtil.setParam("symbol", SinaBaseApi.sinaStockCode(stockVo)); 57 | httpUtil.setParam("startdate", startDate); 58 | httpUtil.setParam("enddate", endDate); 59 | HttpResponseDto httpResponse = httpUtil.request(); 60 | list = this.handleResponse(httpResponse.getContent()); 61 | } catch (IOException e) { 62 | logger.error(e.getMessage()); 63 | } 64 | return list; 65 | } 66 | 67 | /** 68 | * 解析返回的信息 69 | * 70 | * @param response 71 | * @return 72 | */ 73 | private List handleResponse(String response) { 74 | List list = new ArrayList<>(); 75 | //截取表格内容 76 | int bodyStartIndex = response.indexOf(" priceDealNumRatio(StockVo stockVo) { 47 | List list = new ArrayList<>(); 48 | try { 49 | HttpUtil httpUtil = new HttpUtil(); 50 | httpUtil.setUrl(apiUrl) 51 | .setOriCharset(HttpUtil.CHARSET_GBK) 52 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 53 | httpUtil.setParam("symbol", SinaBaseApi.sinaStockCode(stockVo)); 54 | HttpResponseDto httpResponse = httpUtil.request(); 55 | list = this.handleResponse(httpResponse.getContent()); 56 | } catch (IOException e) { 57 | logger.error(e.getMessage()); 58 | } 59 | return list; 60 | } 61 | 62 | /** 63 | * 解析返回的信息 64 | * 65 | * @param response 66 | * @return 67 | */ 68 | private List handleResponse(String response) { 69 | List list = new ArrayList<>(); 70 | int divStartIndex = response.indexOf("
"); 71 | if (0 <= divStartIndex) { 72 | response = response.substring(divStartIndex); 73 | } 74 | int divEndIndex = response.indexOf(" TENCENT_SM_PY_MAP = new HashMap() {{ 35 | put(StockConst.SM_SH, "sh");//沪 36 | put(StockConst.SM_SZ, "sz");//深 37 | put(StockConst.SM_HK, "hk");//港 38 | }}; 39 | 40 | /** 41 | * 获取股市对应的拼音 42 | * 43 | * @param stockMarket 44 | * @return 45 | */ 46 | public static String tencentStockMarketPY(Integer stockMarket) { 47 | return TencentBaseApi.TENCENT_SM_PY_MAP.containsKey(stockMarket) ? 48 | TencentBaseApi.TENCENT_SM_PY_MAP.get(stockMarket) : "sh"; 49 | } 50 | 51 | /** 52 | * 获取腾讯股票代码 53 | * 54 | * @param stockVo 55 | * @return 56 | */ 57 | public static String tencentStockCode(StockVo stockVo) { 58 | if (null == stockVo || null == stockVo.getStockCode() || stockVo.getStockCode().isEmpty() 59 | || null == stockVo.getStockMarket() || !StockConst.SM_ALL.contains(stockVo.getStockMarket())) { 60 | return null; 61 | } 62 | StringBuffer stringBuffer = new StringBuffer(); 63 | stringBuffer.append(TencentBaseApi.tencentStockMarketPY(stockVo.getStockMarket())); 64 | stringBuffer.append(stockVo.getStockCode()); 65 | return stringBuffer.toString(); 66 | } 67 | 68 | /** 69 | * 获取股票信息 70 | * 71 | * @param tencnetStockCode 72 | * @return 73 | */ 74 | public static StockVo tencnetStockCodeToStockVo(String tencnetStockCode) { 75 | if (null == tencnetStockCode || tencnetStockCode.isEmpty()) { 76 | return null; 77 | } 78 | for (Integer stockMarket : TencentBaseApi.TENCENT_SM_PY_MAP.keySet()) { 79 | String stockMarketPY = TencentBaseApi.TENCENT_SM_PY_MAP.get(stockMarket); 80 | if (tencnetStockCode.startsWith(stockMarketPY)) { 81 | String stockCode = tencnetStockCode.replace(stockMarketPY, ""); 82 | return new StockVo(stockCode, stockMarket); 83 | } 84 | } 85 | return null; 86 | } 87 | 88 | /** 89 | * 处理成交量数值差异 90 | * 91 | * @param stockVo 92 | * @param dealNum 93 | * @return 94 | */ 95 | public static Long handleDealNum(StockVo stockVo, String dealNum) { 96 | if (null == stockVo || null == stockVo.getStockMarket() 97 | || !StockConst.SM_ALL.contains(stockVo.getStockMarket())) { 98 | return null; 99 | } 100 | Long longDealNum = new BigDecimal(dealNum).longValue(); 101 | if (StockConst.SM_A_LIST.contains(stockVo.getStockMarket())) { 102 | longDealNum *= 100; 103 | } 104 | return longDealNum; 105 | } 106 | 107 | /** 108 | * 获取交易性质 109 | * 110 | * @param dealTypeStr 111 | * @return 112 | */ 113 | protected static int getDealType(String dealTypeStr) { 114 | switch (dealTypeStr) { 115 | case "B": 116 | return StockConst.DEAL_BUY; 117 | case "S": 118 | return StockConst.DEAL_SELL; 119 | case "M": 120 | return StockConst.DEAL_FLAT; 121 | default: 122 | return StockConst.DEAL_UNKNOWN; 123 | } 124 | } 125 | 126 | /** 127 | * 是否支持该证券所 128 | * 129 | * @param stockMarket 130 | * @return 131 | */ 132 | public static boolean isSupport(int stockMarket) { 133 | return TENCENT_SM_PY_MAP.containsKey(stockMarket); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/tencent/TencentRelateStockApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.tencent; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.tencent.TencentRelateStockPo; 8 | import com.fox.spider.stock.entity.vo.StockVo; 9 | import com.fox.spider.stock.util.HttpUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | import org.springframework.stereotype.Component; 13 | 14 | import java.io.IOException; 15 | import java.util.ArrayList; 16 | import java.util.HashMap; 17 | import java.util.List; 18 | import java.util.Map; 19 | 20 | /** 21 | * 滕讯相关股票列表接口 22 | * 23 | * @author lusongsong 24 | * @date 2020/12/29 17:55 25 | */ 26 | @Component 27 | public class TencentRelateStockApi extends TencentBaseApi { 28 | /** 29 | * 日志 30 | */ 31 | private Logger logger = LoggerFactory.getLogger(getClass()); 32 | /** 33 | * 接口地址 34 | * https://proxy.finance.qq.com/ifzqgtimg/stock/relate/data/relate?code=sz000002 35 | */ 36 | private static final String API_URL = "https://proxy.finance.qq.com/ifzqgtimg/stock/relate/data/relate"; 37 | 38 | /** 39 | * 获取相关股票列表 40 | * 41 | * @param stockVo 42 | * @return 43 | */ 44 | public List relateStock(StockVo stockVo) { 45 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 46 | return null; 47 | } 48 | try { 49 | String tencnetStockCode = TencentBaseApi.tencentStockCode(stockVo); 50 | Map params = new HashMap<>(1); 51 | params.put("code", tencnetStockCode); 52 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 53 | .setParams(params) 54 | .setOriCharset(HttpUtil.CHARSET_GBK) 55 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 56 | HttpResponseDto httpResponse = httpUtil.request(); 57 | List tencentRelateStockPoList = handleResponse(httpResponse.getContent()); 58 | return tencentRelateStockPoList; 59 | } catch (IOException e) { 60 | logger.error(stockVo.toString(), e); 61 | } 62 | return null; 63 | } 64 | 65 | /** 66 | * 解析返回数据 67 | * 68 | * @param response 69 | * @return 70 | */ 71 | private List handleResponse(String response) { 72 | if (null == response || response.isEmpty()) { 73 | return null; 74 | } 75 | try { 76 | JSONObject jsonObject = JSONObject.parseObject(response); 77 | if (null == jsonObject || !jsonObject.containsKey(RESPONSE_KEY_DATA)) { 78 | return null; 79 | } 80 | JSONArray jsonArray = jsonObject.getJSONArray(RESPONSE_KEY_DATA); 81 | if (null == jsonArray || jsonArray.isEmpty()) { 82 | return null; 83 | } 84 | List tencentRelateStockPoList = new ArrayList<>(); 85 | for (int i = 0; i < jsonArray.size(); i++) { 86 | JSONObject relateJSONObject = jsonArray.getJSONObject(i); 87 | if (!relateJSONObject.containsKey(RESPONSE_KEY_CODE) || !relateJSONObject.containsKey(RESPONSE_KEY_NAME)) { 88 | continue; 89 | } 90 | String tencentStockCode = relateJSONObject.getString(RESPONSE_KEY_CODE); 91 | StockVo stockVo = TencentBaseApi.tencnetStockCodeToStockVo(tencentStockCode); 92 | if (null != stockVo) { 93 | TencentRelateStockPo tencentRelateStockPo = new TencentRelateStockPo(); 94 | tencentRelateStockPo.setStockMarket(stockVo.getStockMarket()); 95 | tencentRelateStockPo.setStockCode(stockVo.getStockCode()); 96 | tencentRelateStockPo.setStockName(relateJSONObject.getString(RESPONSE_KEY_NAME)); 97 | tencentRelateStockPoList.add(tencentRelateStockPo); 98 | } 99 | } 100 | return tencentRelateStockPoList; 101 | } catch (JSONException e) { 102 | logger.error(response, e); 103 | } 104 | return null; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaMinuteKLineDataApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.sina.SinaMinuteKLineDataPo; 8 | import com.fox.spider.stock.entity.vo.StockVo; 9 | import com.fox.spider.stock.util.BigDecimalUtil; 10 | import com.fox.spider.stock.util.HttpUtil; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.Arrays; 18 | import java.util.List; 19 | 20 | /** 21 | * 获取分钟粒度成交信息 22 | * 不支持港股 23 | * 返回数据包含当前交易日数据 24 | * scale参数大于等240,时间只有日期 25 | * 240:按天数据 26 | * 1200: 按周数据 27 | * 86400: 按年数据 28 | * 29 | * @author lusongsong 30 | * @date 2020/11/4 16:37 31 | */ 32 | @Component 33 | public class SinaMinuteKLineDataApi extends SinaBaseApi { 34 | /** 35 | * 日志 36 | */ 37 | private Logger logger = LoggerFactory.getLogger(getClass()); 38 | /** 39 | * 样例链接 40 | * http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData?symbol=sz002095&scale=60&ma=no&datalen=1023 41 | */ 42 | /** 43 | * 接口 44 | */ 45 | private static String apiUrl = "http://money.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_MarketData.getKLineData"; 46 | /** 47 | * 支持的时间粒度 48 | */ 49 | private static List scaleList = Arrays.asList(5, 15, 30, 60, 240, 1200, 1680, 86400); 50 | 51 | /** 52 | * 获取分钟粒度成交信息 53 | * 54 | * @param stockVo 55 | * @param scale 56 | * @param dataLen 57 | * @return 58 | */ 59 | public List kLineDataList(StockVo stockVo, Integer scale, Integer dataLen) { 60 | List list = new ArrayList<>(); 61 | try { 62 | if (!scaleList.contains(scale)) { 63 | return list; 64 | } 65 | HttpUtil httpUtil = new HttpUtil(); 66 | httpUtil.setUrl(apiUrl) 67 | .setOriCharset(HttpUtil.CHARSET_GBK) 68 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 69 | httpUtil.setParam("symbol", SinaBaseApi.sinaStockCode(stockVo)); 70 | httpUtil.setParam("scale", Integer.toString(scale)); 71 | httpUtil.setParam("datalen", Integer.toString(dataLen)); 72 | httpUtil.setParam("ma", "no"); 73 | HttpResponseDto httpResponse = httpUtil.request(); 74 | return this.handleResponse(httpResponse.getContent()); 75 | } catch (IOException e) { 76 | logger.error(e.getMessage()); 77 | } finally { 78 | } 79 | return list; 80 | } 81 | 82 | /** 83 | * 处理接口返回 84 | * 85 | * @param response 86 | * @return 87 | */ 88 | private List handleResponse(String response) { 89 | List list = new ArrayList<>(); 90 | try { 91 | //其中的这个data是接口传来的json数据 92 | JSONArray jsonArray = JSONArray.parseArray(response); 93 | int arrayLen = jsonArray.size(); 94 | String day, time; 95 | Integer timePos; 96 | for (int i = 0; i < arrayLen; i++) { 97 | JSONObject jsonObject = jsonArray.getJSONObject(i); 98 | SinaMinuteKLineDataPo stockDealEntity = new SinaMinuteKLineDataPo(); 99 | day = jsonObject.getString("day"); 100 | timePos = day.indexOf(" "); 101 | time = -1 != timePos ? day.substring(timePos + 1) : ""; 102 | day = -1 != timePos ? day.substring(0, timePos) : day; 103 | stockDealEntity.setDt(day); 104 | stockDealEntity.setTime(time); 105 | stockDealEntity.setOpenPrice(BigDecimalUtil.initPrice(jsonObject.getString("open"))); 106 | stockDealEntity.setHighestPrice(BigDecimalUtil.initPrice(jsonObject.getString("high"))); 107 | stockDealEntity.setLowestPrice(BigDecimalUtil.initPrice(jsonObject.getString("low"))); 108 | stockDealEntity.setClosePrice(BigDecimalUtil.initPrice(jsonObject.getString("close"))); 109 | stockDealEntity.setDealNum(jsonObject.getLong("volume")); 110 | list.add(stockDealEntity); 111 | } 112 | } catch (JSONException e) { 113 | logger.error(e.getMessage()); 114 | } 115 | return list; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/test/java/com/fox/spider/stock/api/TencentApiTests.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api; 2 | 3 | import com.fox.spider.stock.StockBaseTests; 4 | import com.fox.spider.stock.api.tencent.*; 5 | import com.fox.spider.stock.constant.StockConst; 6 | import com.fox.spider.stock.entity.vo.PageVo; 7 | import org.junit.jupiter.api.Test; 8 | import org.springframework.beans.factory.annotation.Autowired; 9 | import org.springframework.boot.test.context.SpringBootTest; 10 | 11 | import java.util.Arrays; 12 | 13 | /** 14 | * 腾讯接口测试类 15 | * 16 | * @author lusongsong 17 | * @date 2020/12/24 14:09 18 | */ 19 | @SpringBootTest 20 | public class TencentApiTests extends StockBaseTests { 21 | /** 22 | * 腾讯接口 23 | */ 24 | @Autowired 25 | TencentRealtimeDealInfoApi tencentRealtimeDealInfoApi; 26 | @Autowired 27 | TencentRealtimeMinuteKLineApi tencentRealtimeMinuteKLineApi; 28 | @Autowired 29 | TencentFiveDayMinuteKLineApi tencentFiveDayMinuteKLineApi; 30 | @Autowired 31 | TencentMinuteScopeKLineApi tencentMinuteScopeKLineApi; 32 | @Autowired 33 | TencentKLineApi tencentKLineApi; 34 | @Autowired 35 | TencentRealtimeDealDetailTimeScopeApi tencentRealtimeDealDetailTimeScopeApi; 36 | @Autowired 37 | TencentRealtimeDealDetailApi tencentRealtimeDealDetailApi; 38 | @Autowired 39 | TencentRealtimePriceDealNumApi tencentRealtimePriceDealNumApi; 40 | @Autowired 41 | TencentRelateStockApi tencentRelateStockApi; 42 | @Autowired 43 | TencentRelateBlockApi tencentRelateBlockApi; 44 | @Autowired 45 | TencentBigDealApi tencentBigDealApi; 46 | 47 | /** 48 | * 实时交易数据测试 49 | */ 50 | @Test 51 | void realtimeDealInfoTest() { 52 | System.out.println(tencentRealtimeDealInfoApi.batchRealtimeDealInfo( 53 | Arrays.asList( 54 | TEST_SH_STOCK, 55 | TEST_SZ_STOCK, 56 | TEST_HK_STOCK 57 | )) 58 | ); 59 | } 60 | 61 | /** 62 | * 实时交易分钟线图测试 63 | */ 64 | @Test 65 | void realtimeMinuteKLineTest() { 66 | System.out.println(tencentRealtimeMinuteKLineApi.realtimeMinuteKLine(TEST_SH_STOCK)); 67 | } 68 | 69 | /** 70 | * 腾讯股票5日分钟线图测试 71 | */ 72 | @Test 73 | void fiveDayMinKLineTest() { 74 | System.out.println(tencentFiveDayMinuteKLineApi.fiveDayKLine(TEST_SH_STOCK)); 75 | } 76 | 77 | /** 78 | * 腾讯股票不同分钟粒度线图测试 79 | */ 80 | @Test 81 | void minuteScopeKLineTest() { 82 | System.out.println(tencentMinuteScopeKLineApi.minuteScopeKLine(TEST_SH_STOCK, 5, 200)); 83 | } 84 | 85 | /** 86 | * 腾讯股票K线图测试 87 | */ 88 | @Test 89 | void kLineTest() { 90 | String startDate = "2021-05-25"; 91 | String endDate = "2021-05-20"; 92 | // System.out.println(tencentKLineApi.kLine(TEST_HK_STOCK, StockConst.DT_DAY, StockConst.SFQ_NO, startDate, endDate)); 93 | System.out.println(tencentKLineApi.kLine(TEST_HK_STOCK, StockConst.DT_DAY, StockConst.SFQ_BEFORE, startDate, endDate)); 94 | System.out.println(tencentKLineApi.kLine(TEST_HK_STOCK, StockConst.DT_DAY, StockConst.SFQ_AFTER, startDate, endDate)); 95 | System.out.println(tencentKLineApi.kLine(TEST_HK_STOCK, StockConst.DT_WEEK, StockConst.SFQ_BEFORE, startDate, endDate)); 96 | System.out.println(tencentKLineApi.kLine(TEST_HK_STOCK, StockConst.DT_MONTH, StockConst.SFQ_BEFORE, startDate, endDate)); 97 | } 98 | 99 | /** 100 | * 交易明细测试 101 | */ 102 | @Test 103 | void dealDetailTimeScopeTest() { 104 | System.out.println(tencentRealtimeDealDetailTimeScopeApi.dealDetailTimeScope(TEST_SH_STOCK)); 105 | } 106 | 107 | /** 108 | * 交易明细测试 109 | */ 110 | @Test 111 | void dealDetailTest() { 112 | System.out.println(tencentRealtimeDealDetailApi.dealDetail(TEST_SH_STOCK, 0)); 113 | } 114 | 115 | /** 116 | * 价格成交量测试 117 | */ 118 | @Test 119 | void priceDealNumTest() { 120 | System.out.println(tencentRealtimePriceDealNumApi.priceDealNum(TEST_SH_STOCK)); 121 | } 122 | 123 | /** 124 | * 相关股票测试 125 | */ 126 | @Test 127 | void relateStockTest() { 128 | System.out.println(tencentRelateStockApi.relateStock(TEST_SH_STOCK)); 129 | } 130 | 131 | /** 132 | * 股票所属板块 133 | */ 134 | @Test 135 | void relateBlockTest() { 136 | System.out.println(tencentRelateBlockApi.relateBlock(TEST_SH_STOCK)); 137 | } 138 | 139 | /** 140 | * 大单交易信息 141 | */ 142 | @Test 143 | void bigDealTest() { 144 | System.out.println(tencentBigDealApi.bigDeal( 145 | TEST_SH_STOCK, 1, 0, new PageVo(1, 10)) 146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/nets/NetsFQTotalClosePriceApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.nets; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.fox.spider.stock.constant.StockConst; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.vo.StockVo; 8 | import com.fox.spider.stock.util.BigDecimalUtil; 9 | import com.fox.spider.stock.util.DateUtil; 10 | import com.fox.spider.stock.util.HttpUtil; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.math.BigDecimal; 17 | import java.util.HashMap; 18 | import java.util.Map; 19 | import java.util.TreeMap; 20 | 21 | /** 22 | * 股票不同日期类型复权收盘价 23 | * 24 | * @author lusongsong 25 | * @date 2020/11/6 15:34 26 | */ 27 | @Component 28 | public class NetsFQTotalClosePriceApi extends NetsBaseApi { 29 | /** 30 | * 日志 31 | */ 32 | private Logger logger = LoggerFactory.getLogger(getClass()); 33 | /** 34 | * 样例链接 35 | * http://img1.money.126.net/data/hs/kline/day/times/1399001.json 36 | */ 37 | /** 38 | * 39 | */ 40 | private static String apiUrl = "http://img1.money.126.net/data/" + 41 | "{stockMarketPY}/{rehabilitationType}/{dateType}/times/{stockCode}.json"; 42 | /** 43 | * 复权类型 44 | */ 45 | private static Map fqTypeMap = new HashMap() {{ 46 | put(StockConst.SFQ_BEFORE, "klinederc");//前复权 47 | put(StockConst.SFQ_AFTER, "kline");//后复权 48 | }}; 49 | /** 50 | * 日期类型 51 | */ 52 | private static Map dateTypeMap = new HashMap() {{ 53 | put(StockConst.DT_DAY, "day");//天 54 | put(StockConst.DT_WEEK, "week");//周 55 | put(StockConst.DT_MONTH, "month");//月 56 | }}; 57 | 58 | /** 59 | * 获取不同日期类型复权收盘价 60 | * 61 | * @param stockVo 62 | * @param dateType 63 | * @param fqType 64 | * @return 65 | */ 66 | public Map fqClosePrice(StockVo stockVo, Integer dateType, Integer fqType) { 67 | if (null == stockVo || null == stockVo.getStockCode() || null == stockVo.getStockMarket() 68 | || null == dateType || !dateTypeMap.containsKey(dateType) 69 | || null == fqType || !fqTypeMap.containsKey(fqType)) { 70 | return null; 71 | } 72 | try { 73 | String url = apiUrl.replace("{stockMarketPY}", NetsBaseApi.netsStockMarketPY(stockVo.getStockMarket())) 74 | .replace("{rehabilitationType}", fqTypeMap.get(fqType)) 75 | .replace("{dateType}", dateTypeMap.get(dateType)) 76 | .replace("{stockCode}", NetsBaseApi.netsStockCode(stockVo)); 77 | HttpUtil httpUtil = new HttpUtil(); 78 | httpUtil.setUrl(url).setOriCharset("GBK"); 79 | HttpResponseDto httpResponse = httpUtil.request(); 80 | return this.handleResponse(httpResponse.getContent()); 81 | } catch (IOException e) { 82 | logger.error(e.getMessage()); 83 | } 84 | return null; 85 | } 86 | 87 | /** 88 | * 解析数据返回 89 | * 90 | * @param response 91 | * @return 92 | */ 93 | private Map handleResponse(String response) { 94 | try { 95 | JSONObject responseObj = JSONObject.parseObject(response); 96 | JSONArray closePriceArr = (JSONArray) responseObj.get("closes"); 97 | JSONArray dateArr = (JSONArray) responseObj.get("times"); 98 | if (null == closePriceArr || null == dateArr || closePriceArr.isEmpty() || dateArr.isEmpty()) { 99 | return null; 100 | } 101 | int dateLen = dateArr.size(); 102 | int closePriceLen = closePriceArr.size(); 103 | Map dataMap = new TreeMap<>(); 104 | if (dateLen == closePriceLen) { 105 | for (int i = 0; i < dateLen; i++) { 106 | dataMap.put( 107 | DateUtil.dateStrFormatChange( 108 | dateArr.getString(i), 109 | DateUtil.DATE_FORMAT_2, 110 | DateUtil.DATE_FORMAT_1 111 | ), 112 | BigDecimalUtil.initPrice(closePriceArr.getString(i)) 113 | ); 114 | } 115 | } 116 | return dataMap; 117 | } catch (Exception e) { 118 | logger.error(e.getMessage()); 119 | } 120 | return null; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/tencent/TencentKLineBaseApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.tencent; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.po.tencent.TencentRealtimeMinuteNodeDataPo; 7 | import com.fox.spider.stock.entity.vo.StockVo; 8 | import com.fox.spider.stock.util.BigDecimalUtil; 9 | import com.fox.spider.stock.util.DateUtil; 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | import java.math.BigDecimal; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * 腾讯股票线图基类 19 | * 20 | * @author lusongsong 21 | * @date 2020/12/28 15:43 22 | */ 23 | public class TencentKLineBaseApi extends TencentBaseApi { 24 | /** 25 | * 日志 26 | */ 27 | private Logger logger = LoggerFactory.getLogger(getClass()); 28 | /** 29 | * 分钟交易信息分割符 30 | */ 31 | protected static String MIN_DEAL_INFO_SPLIT_STR = " "; 32 | /** 33 | * 返回数据交易信息key 34 | */ 35 | protected static String RESPONSE_KEY_QT = "qt"; 36 | /** 37 | * 返回数据日期key 38 | */ 39 | protected static String RESPONSE_KEY_DATE = "date"; 40 | /** 41 | * 返回数据上个交易日收盘价 42 | */ 43 | protected static String RESPONSE_KEY_PRE_CLOSE_PRICE = "prec"; 44 | 45 | /** 46 | * 解析股票返回数据,获取信息JSONObject 47 | * 48 | * @param stockVo 49 | * @param response 50 | * @return 51 | */ 52 | protected JSONObject getResponseJSONObject(StockVo stockVo, String response) { 53 | int infoStartIndex = response.indexOf("{"); 54 | if (-1 == infoStartIndex) { 55 | return null; 56 | } 57 | String stockCode = TencentBaseApi.tencentStockCode(stockVo); 58 | try { 59 | response = response.substring(infoStartIndex); 60 | JSONObject jsonObject = JSONObject.parseObject(response); 61 | if (null == jsonObject || !jsonObject.containsKey(RESPONSE_KEY_DATA)) { 62 | return null; 63 | } 64 | jsonObject = jsonObject.getJSONObject(RESPONSE_KEY_DATA); 65 | if (null == jsonObject || !jsonObject.containsKey(stockCode)) { 66 | return null; 67 | } 68 | jsonObject = jsonObject.getJSONObject(stockCode); 69 | return jsonObject; 70 | } catch (JSONException e) { 71 | logger.error(stockVo.toString()); 72 | logger.error(response, e); 73 | } 74 | return null; 75 | } 76 | 77 | /** 78 | * 处理天分钟数据 79 | * 80 | * @param stockVo 81 | * @param minKLineArr 82 | * @return 83 | */ 84 | protected List handleDayMinArr(StockVo stockVo, JSONArray minKLineArr) { 85 | if (null != minKLineArr && !minKLineArr.isEmpty()) { 86 | List tencentRealtimeMinuteNodeDataPoList = new ArrayList<>(); 87 | Long totalDealNum = 0L; 88 | Long currentTotalDealNum = 0L; 89 | for (int i = 0; i < minKLineArr.size(); i++) { 90 | String minDealInfoStr = minKLineArr.getString(i); 91 | if (null == minDealInfoStr || minDealInfoStr.isEmpty() 92 | || minDealInfoStr.contains(MIN_DEAL_INFO_SPLIT_STR)) { 93 | String[] minDealInfoArr = minDealInfoStr.split(MIN_DEAL_INFO_SPLIT_STR); 94 | if (3 != minDealInfoArr.length) { 95 | continue; 96 | } 97 | TencentRealtimeMinuteNodeDataPo tencentRealtimeMinuteNodeDataPo = 98 | new TencentRealtimeMinuteNodeDataPo(); 99 | tencentRealtimeMinuteNodeDataPo.setTime( 100 | DateUtil.dateStrFormatChange( 101 | minDealInfoArr[0], 102 | DateUtil.TIME_FORMAT_5, 103 | DateUtil.TIME_FORMAT_6 104 | ) 105 | ); 106 | tencentRealtimeMinuteNodeDataPo.setPrice(BigDecimalUtil.initPrice(minDealInfoArr[1])); 107 | currentTotalDealNum = new BigDecimal(minDealInfoArr[2]).longValue(); 108 | tencentRealtimeMinuteNodeDataPo.setDealNum( 109 | handleDealNum(stockVo, String.valueOf(currentTotalDealNum - totalDealNum)) 110 | ); 111 | totalDealNum = currentTotalDealNum; 112 | tencentRealtimeMinuteNodeDataPoList.add(tencentRealtimeMinuteNodeDataPo); 113 | } 114 | } 115 | return tencentRealtimeMinuteNodeDataPoList; 116 | } 117 | return null; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengRealtimePriceDealNumApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.po.ifeng.IFengRealtimePriceDealNumPo; 5 | import com.fox.spider.stock.entity.vo.StockVo; 6 | import com.fox.spider.stock.util.BigDecimalUtil; 7 | import org.jsoup.Jsoup; 8 | import org.jsoup.nodes.Document; 9 | import org.jsoup.nodes.Element; 10 | import org.jsoup.select.Elements; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 凤凰网价格成交量信息 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/7 18:28 24 | */ 25 | @Component 26 | public class IFengRealtimePriceDealNumApi extends IFengBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 接口地址 33 | * http://app.finance.ifeng.com/data/stock/stock_stat3.php?code=sz002475 34 | */ 35 | private static final String API_URL = "http://app.finance.ifeng.com/data/stock/stock_stat3.php?code="; 36 | 37 | /** 38 | * 获取大单交易数据 39 | * 40 | * @param stockVo 41 | * @return 42 | */ 43 | public List priceDealNum(StockVo stockVo) { 44 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 45 | return null; 46 | } 47 | try { 48 | String iFengStockCode = iFengStockCode(stockVo); 49 | Document document = Jsoup.connect(API_URL + iFengStockCode).get(); 50 | return handleResponse(document); 51 | } catch (IOException e) { 52 | logger.error(stockVo.toString(), e); 53 | } 54 | return null; 55 | } 56 | 57 | /** 58 | * 处理返回数据 59 | * 60 | * @param document 61 | * @return 62 | */ 63 | private List handleResponse(Document document) { 64 | List iFengRealtimePriceDealNumPoList = null; 65 | if (null != document) { 66 | Elements tableElements = document.body().getElementsByTag("table"); 67 | if (null != tableElements && !tableElements.isEmpty()) { 68 | Element tableElement = tableElements.first(); 69 | Elements trElements = tableElement.getElementsByTag("tr"); 70 | if (null != trElements && !trElements.isEmpty()) { 71 | for (Element trElement : trElements) { 72 | if (null != trElement) { 73 | Elements tdElements = trElement.children(); 74 | IFengRealtimePriceDealNumPo iFengRealtimePriceDealNumPo = handleRow(tdElements); 75 | if (null != iFengRealtimePriceDealNumPo) { 76 | iFengRealtimePriceDealNumPoList = null == iFengRealtimePriceDealNumPoList ? 77 | new ArrayList<>() : iFengRealtimePriceDealNumPoList; 78 | iFengRealtimePriceDealNumPoList.add(iFengRealtimePriceDealNumPo); 79 | } 80 | } 81 | } 82 | } 83 | } 84 | } 85 | return iFengRealtimePriceDealNumPoList; 86 | } 87 | 88 | /** 89 | * 处理单条大单交易 90 | * 91 | * @param tdElements 92 | * @return 93 | */ 94 | private IFengRealtimePriceDealNumPo handleRow(Elements tdElements) { 95 | IFengRealtimePriceDealNumPo iFengRealtimePriceDealNumPo = null; 96 | if (null != tdElements && !tdElements.isEmpty()) { 97 | for (int i = 0; i < tdElements.size(); i++) { 98 | Element tdElement = tdElements.get(i); 99 | if (tdElement.getElementsByTag("th").isEmpty()) { 100 | iFengRealtimePriceDealNumPo = null == iFengRealtimePriceDealNumPo ? 101 | new IFengRealtimePriceDealNumPo() : iFengRealtimePriceDealNumPo; 102 | String text = tdElement.text(); 103 | if (0 == i) { 104 | iFengRealtimePriceDealNumPo.setPrice(BigDecimalUtil.initPrice(text)); 105 | } else if (1 == i) { 106 | iFengRealtimePriceDealNumPo.setDealNum(BigDecimalUtil.initLong(text)); 107 | } else if (2 == i) { 108 | text = text.replace("%", ""); 109 | iFengRealtimePriceDealNumPo.setRatio(BigDecimalUtil.initRate(text)); 110 | } 111 | 112 | } 113 | } 114 | } 115 | return iFengRealtimePriceDealNumPo; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/tencent/TencentRealtimeDealDetailTimeScopeApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.tencent; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 6 | import com.fox.spider.stock.entity.vo.StockVo; 7 | import com.fox.spider.stock.util.HttpUtil; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.slf4j.Logger; 10 | import org.slf4j.LoggerFactory; 11 | import org.springframework.stereotype.Component; 12 | 13 | import java.io.IOException; 14 | import java.util.ArrayList; 15 | import java.util.HashMap; 16 | import java.util.List; 17 | import java.util.Map; 18 | 19 | /** 20 | * 腾讯股票交易实时明细时间范围列表 21 | * 22 | * @author lusongsong 23 | * @date 2020/12/29 16:40 24 | */ 25 | @Component 26 | public class TencentRealtimeDealDetailTimeScopeApi extends TencentBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 接口地址 33 | * https://stock.gtimg.cn/data/index.php?appn=detail&action=timeline&c=sh603383 34 | */ 35 | private static final String API_URL = "https://stock.gtimg.cn/data/index.php"; 36 | /** 37 | * 时间范围分割符 38 | */ 39 | private static String SCOPE_SPLIT_STR = "|"; 40 | /** 41 | * 时间分割符 42 | */ 43 | private static String TIME_SPLIT_STR = "~"; 44 | 45 | /** 46 | * 获取交易实时明细时间范围列表 47 | * 48 | * @param stockVo 49 | * @return 50 | */ 51 | public List> dealDetailTimeScope(StockVo stockVo) { 52 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 53 | return null; 54 | } 55 | try { 56 | String tencnetStockCode = TencentBaseApi.tencentStockCode(stockVo); 57 | Map params = new HashMap<>(4); 58 | params.put("appn", "detail"); 59 | params.put("action", "timeline"); 60 | params.put("c", tencnetStockCode); 61 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 62 | .setParams(params) 63 | .setOriCharset(HttpUtil.CHARSET_GBK) 64 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 65 | HttpResponseDto httpResponse = httpUtil.request(); 66 | List> dealDetailTimeScopeList = this.handleResponse( 67 | stockVo, httpResponse.getContent() 68 | ); 69 | return dealDetailTimeScopeList; 70 | } catch (IOException e) { 71 | logger.error(stockVo.toString(), e); 72 | } 73 | return null; 74 | } 75 | 76 | /** 77 | * 解析返回数据 78 | * 79 | * @param stockVo 80 | * @param response 81 | * @return 82 | */ 83 | private List> handleResponse(StockVo stockVo, String response) { 84 | if (null == stockVo || null == response || response.isEmpty()) { 85 | return null; 86 | } 87 | try { 88 | int infoStartIndex = response.indexOf("["); 89 | if (-1 == infoStartIndex) { 90 | return null; 91 | } 92 | response = response.substring(infoStartIndex); 93 | JSONArray jsonArray = JSONArray.parseArray(response); 94 | if (null == jsonArray || jsonArray.isEmpty() || 2 != jsonArray.size()) { 95 | return null; 96 | } 97 | String timeScopeStr = jsonArray.getString(1); 98 | if (null == timeScopeStr || timeScopeStr.isEmpty()) { 99 | return null; 100 | } 101 | String[] dealDetailArr = StringUtils.split(timeScopeStr, SCOPE_SPLIT_STR); 102 | List> timeScopeList = new ArrayList<>(); 103 | for (int i = 0; i < dealDetailArr.length; i++) { 104 | String singleTimeScopeStr = dealDetailArr[i]; 105 | if (null == singleTimeScopeStr || singleTimeScopeStr.isEmpty()) { 106 | continue; 107 | } 108 | List scopeList = handleSingleTimeScope(singleTimeScopeStr); 109 | if (null != scopeList) { 110 | timeScopeList.add(scopeList); 111 | } 112 | } 113 | return timeScopeList; 114 | } catch (JSONException e) { 115 | logger.error(response, e); 116 | } 117 | return null; 118 | } 119 | 120 | /** 121 | * 处理单条时间范围 122 | * 123 | * @param singleTimeScopeStr 124 | * @return 125 | */ 126 | private List handleSingleTimeScope(String singleTimeScopeStr) { 127 | if (null == singleTimeScopeStr || singleTimeScopeStr.isEmpty()) { 128 | return null; 129 | } 130 | String[] timeScopeInfoArr = StringUtils.split(singleTimeScopeStr, TIME_SPLIT_STR); 131 | if (null == timeScopeInfoArr || 2 != timeScopeInfoArr.length) { 132 | return null; 133 | } 134 | List scopeList = new ArrayList<>(2); 135 | for (int i = 0; i < timeScopeInfoArr.length; i++) { 136 | scopeList.add(timeScopeInfoArr[i]); 137 | } 138 | return scopeList; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sz/SZStockInfoApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sz; 2 | 3 | import com.alibaba.fastjson.JSONObject; 4 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 5 | import com.fox.spider.stock.entity.po.sz.SZStockInfoPo; 6 | import com.fox.spider.stock.util.HttpUtil; 7 | import org.slf4j.Logger; 8 | import org.slf4j.LoggerFactory; 9 | import org.springframework.stereotype.Component; 10 | 11 | import java.math.BigDecimal; 12 | import java.util.Arrays; 13 | import java.util.List; 14 | 15 | /** 16 | * 深市股票信息接口类 17 | * 18 | * @author lusongsong 19 | * @date 2020/11/20 14:29 20 | */ 21 | @Component 22 | public class SZStockInfoApi extends SZBaseApi { 23 | /** 24 | * 日志 25 | */ 26 | private Logger logger = LoggerFactory.getLogger(getClass()); 27 | /** 28 | * 接口地址 29 | */ 30 | private static final String API_URL = "http://www.szse.cn/api/report/index/companyGeneralization"; 31 | /** 32 | * 股票类型 33 | */ 34 | private static final List TYPE_LIST = Arrays.asList("a", "b"); 35 | 36 | /** 37 | * 获取深市股票信息 38 | * 39 | * @param stockCode 40 | * @return 41 | */ 42 | public SZStockInfoPo stockInfo(String stockCode) { 43 | if (null == stockCode || stockCode.isEmpty()) { 44 | return null; 45 | } 46 | 47 | try { 48 | HttpUtil httpUtil = new HttpUtil(); 49 | httpUtil.setUrl(API_URL); 50 | httpUtil.setParam("secCode", stockCode); 51 | HttpResponseDto httpResponse = httpUtil.request(); 52 | String responseContent = httpResponse.getContent(); 53 | if (null != responseContent && !responseContent.equals("")) { 54 | JSONObject baseObject = JSONObject.parseObject(responseContent); 55 | if (!baseObject.isEmpty() && baseObject.containsKey("data")) { 56 | JSONObject dataObject = baseObject.getJSONObject("data"); 57 | if (null != dataObject) { 58 | SZStockInfoPo szStockInfoPo = new SZStockInfoPo(); 59 | szStockInfoPo.setStockCode(stockCode); 60 | String stockCodeKey; 61 | String typeStr = TYPE_LIST.get(0); 62 | for (String type : TYPE_LIST) { 63 | stockCodeKey = type + "gdm"; 64 | if (dataObject.containsKey(stockCodeKey) && stockCode.equals(dataObject.getString(stockCodeKey))) { 65 | typeStr = type; 66 | break; 67 | } 68 | } 69 | 70 | if (dataObject.containsKey(typeStr + "gjc")) { 71 | szStockInfoPo.setStockName(dataObject.getString(typeStr + "gjc")); 72 | } 73 | if (dataObject.containsKey(typeStr + "gdm")) { 74 | szStockInfoPo.setStockCode(dataObject.getString(typeStr + "gdm")); 75 | } 76 | if (dataObject.containsKey(typeStr + "gzgb")) { 77 | szStockInfoPo.setStockTotalEquity(new BigDecimal(dataObject.getString(typeStr + "gzgb").replace(",", ""))); 78 | } 79 | if (dataObject.containsKey(typeStr + "gltgb")) { 80 | szStockInfoPo.setStockCircEquity(new BigDecimal(dataObject.getString(typeStr + "gltgb").replace(",", ""))); 81 | } 82 | if (dataObject.containsKey(typeStr + "gssrq")) { 83 | szStockInfoPo.setStockOnDate(dataObject.getString(typeStr + "gssrq")); 84 | } 85 | if (dataObject.containsKey("gsqc")) { 86 | szStockInfoPo.setStockFullName(dataObject.getString("gsqc")); 87 | } 88 | if (dataObject.containsKey("ywqc")) { 89 | szStockInfoPo.setStockFullNameEn(dataObject.getString("ywqc")); 90 | } 91 | if (dataObject.containsKey("zcdz")) { 92 | szStockInfoPo.setStockRegisterAddress(dataObject.getString("zcdz")); 93 | } 94 | if (dataObject.containsKey("http")) { 95 | szStockInfoPo.setStockWebsite(dataObject.getString("http")); 96 | } 97 | if (dataObject.containsKey("dldq")) { 98 | szStockInfoPo.setStockArea(dataObject.getString("dldq")); 99 | } 100 | if (dataObject.containsKey("sheng")) { 101 | szStockInfoPo.setStockProvince(dataObject.getString("sheng")); 102 | } 103 | if (dataObject.containsKey("shi")) { 104 | szStockInfoPo.setStockCity(dataObject.getString("shi")); 105 | } 106 | if (dataObject.containsKey("sshymc")) { 107 | szStockInfoPo.setStockIndustry(dataObject.getString("sshymc")); 108 | } 109 | return szStockInfoPo; 110 | } 111 | } 112 | } 113 | } catch (Exception e) { 114 | logger.error(e.getMessage()); 115 | } 116 | return null; 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengRealtimeBigDealApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.po.ifeng.IFengRealtimeBigDealPo; 5 | import com.fox.spider.stock.entity.vo.StockVo; 6 | import com.fox.spider.stock.util.BigDecimalUtil; 7 | import org.jsoup.Jsoup; 8 | import org.jsoup.nodes.Document; 9 | import org.jsoup.nodes.Element; 10 | import org.jsoup.select.Elements; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 凤凰网大单交易信息 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/7 15:24 24 | */ 25 | @Component 26 | public class IFengRealtimeBigDealApi extends IFengBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 接口地址 33 | * http://app.finance.ifeng.com/hq/stock_bill.php?code=sz002475 34 | */ 35 | private static final String API_URL = "http://app.finance.ifeng.com/hq/stock_bill.php?code="; 36 | 37 | /** 38 | * 获取交易类型 39 | * 40 | * @param text 41 | * @return 42 | */ 43 | private int getDealType(String text) { 44 | switch (text) { 45 | case "买盘": 46 | return StockConst.DEAL_BUY; 47 | case "卖盘": 48 | return StockConst.DEAL_SELL; 49 | case "其他": 50 | case "中性盘": 51 | return StockConst.DEAL_FLAT; 52 | default: 53 | return StockConst.DEAL_UNKNOWN; 54 | } 55 | } 56 | 57 | /** 58 | * 获取大单交易数据 59 | * 60 | * @param stockVo 61 | * @return 62 | */ 63 | public List bigDeal(StockVo stockVo) { 64 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 65 | return null; 66 | } 67 | try { 68 | String iFengStockCode = iFengStockCode(stockVo); 69 | Document document = Jsoup.connect(API_URL + iFengStockCode).get(); 70 | return handleResponse(document); 71 | } catch (IOException e) { 72 | logger.error(stockVo.toString(), e); 73 | } 74 | return null; 75 | } 76 | 77 | /** 78 | * 处理返回数据 79 | * 80 | * @param document 81 | * @return 82 | */ 83 | private List handleResponse(Document document) { 84 | List iFengRealtimeBigDealPoList = null; 85 | if (null != document) { 86 | Elements tableElements = document.body().getElementsByTag("table"); 87 | if (null != tableElements && !tableElements.isEmpty()) { 88 | Element tableElement = tableElements.first(); 89 | Elements trElements = tableElement.getElementsByTag("tr"); 90 | if (null != trElements && !trElements.isEmpty()) { 91 | for (Element trElement : trElements) { 92 | if (null != trElement) { 93 | Elements tdElements = trElement.children(); 94 | IFengRealtimeBigDealPo iFengRealtimeBigDealPo = handleRow(tdElements); 95 | if (null != iFengRealtimeBigDealPo) { 96 | iFengRealtimeBigDealPoList = null == iFengRealtimeBigDealPoList ? 97 | new ArrayList<>() : iFengRealtimeBigDealPoList; 98 | iFengRealtimeBigDealPoList.add(iFengRealtimeBigDealPo); 99 | } 100 | } 101 | } 102 | } 103 | } 104 | } 105 | return iFengRealtimeBigDealPoList; 106 | } 107 | 108 | /** 109 | * 处理单条大单交易 110 | * 111 | * @param tdElements 112 | * @return 113 | */ 114 | private IFengRealtimeBigDealPo handleRow(Elements tdElements) { 115 | IFengRealtimeBigDealPo iFengRealtimeBigDealPo = null; 116 | if (null != tdElements && !tdElements.isEmpty()) { 117 | for (int i = 0; i < tdElements.size(); i++) { 118 | Element tdElement = tdElements.get(i); 119 | if (tdElement.attr("width").isEmpty()) { 120 | iFengRealtimeBigDealPo = null == iFengRealtimeBigDealPo ? 121 | new IFengRealtimeBigDealPo() : iFengRealtimeBigDealPo; 122 | String text = tdElement.text(); 123 | if (0 == i) { 124 | iFengRealtimeBigDealPo.setTime(text); 125 | } else if (1 == i) { 126 | iFengRealtimeBigDealPo.setPrice(BigDecimalUtil.initPrice(text)); 127 | } else if (2 == i) { 128 | iFengRealtimeBigDealPo.setDealNum(BigDecimalUtil.initLong(text)); 129 | } else if (3 == i) { 130 | iFengRealtimeBigDealPo.setDealMoney(BigDecimalUtil.initPrice(text)); 131 | } else if (4 == i) { 132 | iFengRealtimeBigDealPo.setDealType(getDealType(text)); 133 | } else if (5 == i) { 134 | iFengRealtimeBigDealPo.setUptickPrice(BigDecimalUtil.initPrice(text)); 135 | } else if (6 == i) { 136 | text = text.replace("%", ""); 137 | iFengRealtimeBigDealPo.setUptickRate(BigDecimalUtil.initRate(text)); 138 | } 139 | 140 | } 141 | } 142 | } 143 | return iFengRealtimeBigDealPo; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/constant/StockMarketStatusConst.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.constant; 2 | 3 | import com.fox.spider.stock.util.DateUtil; 4 | 5 | import java.util.*; 6 | 7 | /** 8 | * 股市交易状态常量 9 | * 10 | * @author lusongsong 11 | * @date 2020/11/9 16:50 12 | */ 13 | public class StockMarketStatusConst { 14 | /** 15 | * 未知的状态 16 | */ 17 | public static final int UNKNOWN = 0; 18 | /** 19 | * 未知描述 20 | */ 21 | public static final String DESC_UNKNOWN = "未知"; 22 | /** 23 | * 开盘 24 | */ 25 | public static final int OPEN = 1; 26 | /** 27 | * 开盘描述 28 | */ 29 | public static final String DESC_OPEN = "开盘中"; 30 | /** 31 | * 收盘 32 | */ 33 | public static final int CLOSE = 2; 34 | /** 35 | * 收盘描述 36 | */ 37 | public static final String DESC_CLOSE = "已收盘"; 38 | /** 39 | * 休市 40 | */ 41 | public static final int REST = 3; 42 | /** 43 | * 休市描述 44 | */ 45 | public static final String DESC_REST = "休市"; 46 | /** 47 | * 竞价 48 | */ 49 | public static final int COMPETE = 4; 50 | /** 51 | * 竞价描述 52 | */ 53 | public static final String DESC_COMPETE = "竞价中"; 54 | /** 55 | * 未开盘 56 | */ 57 | public static final int INIT = 5; 58 | /** 59 | * 未开盘描述 60 | */ 61 | public static final String DESC_INIT = "未开盘"; 62 | /** 63 | * 午间休息 64 | */ 65 | public static final int NOON = 6; 66 | /** 67 | * 午间休息描述 68 | */ 69 | public static final String DESC_NOON = "午间休息"; 70 | /** 71 | * 即将开盘 72 | */ 73 | public static final int SOON = 7; 74 | /** 75 | * 即将开盘藐视 76 | */ 77 | public static final String DESC_SOON = "即将开盘"; 78 | /** 79 | * 状态名称对应 80 | */ 81 | public static final Map STATUS_DESC_MAP = new HashMap() {{ 82 | put(UNKNOWN, DESC_UNKNOWN); 83 | put(OPEN, DESC_OPEN); 84 | put(CLOSE, DESC_CLOSE); 85 | put(REST, DESC_REST); 86 | put(COMPETE, DESC_COMPETE); 87 | put(INIT, DESC_INIT); 88 | put(NOON, DESC_NOON); 89 | put(SOON, DESC_SOON); 90 | }}; 91 | 92 | /** 93 | * 可以交易的状态列表 94 | */ 95 | public static final List CAN_DEAL_STATUS_LIST = Arrays.asList(OPEN, COMPETE); 96 | 97 | /** 98 | * A股交易日不同时间交易状态 99 | * 100 | * @return 101 | */ 102 | public static Integer aTimeSMStatus() { 103 | Calendar calendar = DateUtil.currentTime(); 104 | int hour = calendar.get(Calendar.HOUR_OF_DAY); 105 | int minutes = calendar.get(Calendar.MINUTE); 106 | if (0 <= hour && hour < 9) { 107 | return StockMarketStatusConst.INIT; 108 | } else if (9 <= hour && hour < 10) { 109 | if (0 <= minutes && minutes < 15) { 110 | return StockMarketStatusConst.INIT; 111 | } else if (15 <= minutes && minutes < 25) { 112 | return StockMarketStatusConst.COMPETE; 113 | } else if (25 <= minutes && minutes < 30) { 114 | return StockMarketStatusConst.SOON; 115 | } else { 116 | return StockMarketStatusConst.OPEN; 117 | } 118 | } else if (10 <= hour && hour < 11) { 119 | return StockMarketStatusConst.OPEN; 120 | } else if (11 <= hour && hour < 12) { 121 | if (30 > minutes) { 122 | return StockMarketStatusConst.OPEN; 123 | } else { 124 | return StockMarketStatusConst.NOON; 125 | } 126 | } else if (12 <= hour && hour < 13) { 127 | return StockMarketStatusConst.NOON; 128 | } else if (13 <= hour && hour < 15) { 129 | return StockMarketStatusConst.OPEN; 130 | } else { 131 | return StockMarketStatusConst.CLOSE; 132 | } 133 | } 134 | 135 | /** 136 | * 港股交易日不同时间交易状态 137 | * 138 | * @return 139 | */ 140 | public static Integer hkTimeSMStatus() { 141 | Calendar calendar = DateUtil.currentTime(); 142 | int hour = calendar.get(Calendar.HOUR_OF_DAY); 143 | int minutes = calendar.get(Calendar.MINUTE); 144 | if (0 <= hour && hour < 9) { 145 | return StockMarketStatusConst.INIT; 146 | } else if (9 <= hour && hour < 10) { 147 | if (0 <= minutes && minutes < 30) { 148 | return StockMarketStatusConst.COMPETE; 149 | } else { 150 | return StockMarketStatusConst.OPEN; 151 | } 152 | } else if (10 <= hour && hour < 12) { 153 | return StockMarketStatusConst.OPEN; 154 | } else if (12 <= hour && hour < 13) { 155 | return StockMarketStatusConst.NOON; 156 | } else if (13 <= hour && hour < 16) { 157 | return StockMarketStatusConst.OPEN; 158 | } else if (16 <= hour && hour < 17) { 159 | if (0 <= minutes && minutes < 10) { 160 | return StockMarketStatusConst.COMPETE; 161 | } else { 162 | return StockMarketStatusConst.CLOSE; 163 | } 164 | } else { 165 | return StockMarketStatusConst.CLOSE; 166 | } 167 | } 168 | 169 | /** 170 | * 获取股市交易日不同时间交易状态 171 | * 172 | * @param stockMarket 173 | * @return 174 | */ 175 | public static Integer timeSMStatus(Integer stockMarket) { 176 | if (null == stockMarket) { 177 | return null; 178 | } 179 | switch (stockMarket) { 180 | case StockConst.SM_SH: 181 | case StockConst.SM_SZ: 182 | return aTimeSMStatus(); 183 | case StockConst.SM_HK: 184 | return hkTimeSMStatus(); 185 | default: 186 | return null; 187 | } 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/nets/NetsRealtimeMinuteKLineApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.nets; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONObject; 5 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 6 | import com.fox.spider.stock.entity.po.nets.NetsRealtimeMinuteKLinePo; 7 | import com.fox.spider.stock.entity.po.nets.NetsRealtimeMinuteNodeDataPo; 8 | import com.fox.spider.stock.entity.vo.StockVo; 9 | import com.fox.spider.stock.util.BigDecimalUtil; 10 | import com.fox.spider.stock.util.DateUtil; 11 | import com.fox.spider.stock.util.HttpUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.io.IOException; 17 | import java.util.ArrayList; 18 | import java.util.List; 19 | 20 | /** 21 | * 股票实时交易分钟线图数据 22 | * 23 | * @author lusongsong 24 | * @date 2020/11/6 15:21 25 | */ 26 | @Component 27 | public class NetsRealtimeMinuteKLineApi extends NetsBaseApi { 28 | /** 29 | * 日志 30 | */ 31 | private Logger logger = LoggerFactory.getLogger(getClass()); 32 | /** 33 | * 样例链接 34 | * http://img1.money.126.net/data/hs/time/today/1399001.json 35 | */ 36 | /** 37 | * 接口 38 | */ 39 | private static String apiUrl = "http://img1.money.126.net/data/{stockMarketPY}/time/today/{stockCode}.json"; 40 | 41 | /** 42 | * 获取实时交易分钟线图数据 43 | * 44 | * @param stockVo 45 | * @return 46 | */ 47 | public NetsRealtimeMinuteKLinePo realtimeMinuteKLine(StockVo stockVo) { 48 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 49 | return null; 50 | } 51 | try { 52 | String url = apiUrl.replace("{stockCode}", NetsBaseApi.netsStockCode(stockVo)) 53 | .replace("{stockMarketPY}", NetsBaseApi.netsStockMarketPY(stockVo.getStockMarket())); 54 | HttpUtil httpUtil = new HttpUtil(); 55 | httpUtil.setUrl(url).setOriCharset("GBK"); 56 | HttpResponseDto httpResponse = httpUtil.request(); 57 | NetsRealtimeMinuteKLinePo netsRealtimeMinuteKLinePo = this.handleResponse(httpResponse.getContent()); 58 | if (null != netsRealtimeMinuteKLinePo) { 59 | netsRealtimeMinuteKLinePo.setStockMarket(stockVo.getStockMarket()); 60 | netsRealtimeMinuteKLinePo.setStockCode(stockVo.getStockCode()); 61 | } 62 | return netsRealtimeMinuteKLinePo; 63 | } catch (IOException e) { 64 | logger.error(e.getMessage()); 65 | } 66 | return null; 67 | } 68 | 69 | /** 70 | * 处理返回数据 71 | * 72 | * @param response 73 | * @return 74 | */ 75 | private NetsRealtimeMinuteKLinePo handleResponse(String response) { 76 | if (null == response || response.isEmpty()) { 77 | return null; 78 | } 79 | 80 | try { 81 | NetsRealtimeMinuteKLinePo netsRealtimeMinuteKLinePo = new NetsRealtimeMinuteKLinePo(); 82 | JSONObject responseObject = JSONObject.parseObject(response); 83 | if (responseObject.containsKey("count")) { 84 | netsRealtimeMinuteKLinePo.setNodeCount(responseObject.getInteger("count")); 85 | } 86 | if (responseObject.containsKey("symbol")) { 87 | netsRealtimeMinuteKLinePo.setStockCode(responseObject.getString("symbol")); 88 | } 89 | if (responseObject.containsKey("name")) { 90 | netsRealtimeMinuteKLinePo.setStockName(responseObject.getString("name").replace(" ", "")); 91 | } 92 | if (responseObject.containsKey("yestclose")) { 93 | netsRealtimeMinuteKLinePo.setPreClosePrice( 94 | BigDecimalUtil.initPrice(responseObject.getString("yestclose")) 95 | ); 96 | } 97 | if (responseObject.containsKey("lastVolume")) { 98 | netsRealtimeMinuteKLinePo.setDealNum( 99 | BigDecimalUtil.initLong(responseObject.getString("lastVolume")) 100 | ); 101 | } 102 | if (responseObject.containsKey("date")) { 103 | netsRealtimeMinuteKLinePo.setDt( 104 | DateUtil.dateStrFormatChange( 105 | responseObject.getString("date"), 106 | DateUtil.DATE_FORMAT_2, 107 | DateUtil.DATE_FORMAT_1 108 | ) 109 | ); 110 | } 111 | if (responseObject.containsKey("data")) { 112 | JSONArray dataArr = (JSONArray) responseObject.get("data"); 113 | List nodeList = new ArrayList<>(); 114 | int dataLen = dataArr.size(); 115 | for (int i = 0; i < dataLen; i++) { 116 | JSONArray noteArr = (JSONArray) dataArr.get(i); 117 | if (4 == noteArr.size()) { 118 | NetsRealtimeMinuteNodeDataPo netsRealtimeMinuteNodeDataPo = new NetsRealtimeMinuteNodeDataPo(); 119 | String timeStr = noteArr.getString(0); 120 | netsRealtimeMinuteNodeDataPo.setTime(timeStr.substring(0, 2) + ":" + timeStr.substring(2, 4)); 121 | netsRealtimeMinuteNodeDataPo.setPrice(BigDecimalUtil.initPrice(noteArr.getString(1))); 122 | netsRealtimeMinuteNodeDataPo.setAvgPrice(BigDecimalUtil.initPrice(noteArr.getString(2))); 123 | netsRealtimeMinuteNodeDataPo.setDealNum(noteArr.getLong(3)); 124 | nodeList.add(netsRealtimeMinuteNodeDataPo); 125 | } 126 | } 127 | if (nodeList.size() > 0) { 128 | netsRealtimeMinuteKLinePo.setKlineData(nodeList); 129 | } 130 | } 131 | return netsRealtimeMinuteKLinePo; 132 | } catch (Exception e) { 133 | logger.error(e.getMessage()); 134 | } 135 | return null; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengKLineApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.constant.StockConst; 7 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 8 | import com.fox.spider.stock.entity.po.ifeng.IFengKLinePo; 9 | import com.fox.spider.stock.entity.vo.StockVo; 10 | import com.fox.spider.stock.util.BigDecimalUtil; 11 | import com.fox.spider.stock.util.HttpUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.io.IOException; 17 | import java.util.*; 18 | 19 | /** 20 | * 凤凰网天周月线图数据 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/6 16:40 24 | */ 25 | @Component 26 | public class IFengKLineApi extends IFengBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 接口地址 33 | * https://api.finance.ifeng.com/akmonthly/?code=sz300033&type=last 34 | */ 35 | private static final String API_URL = "https://api.finance.ifeng.com/"; 36 | /** 37 | * 支持日期类型范围类别 38 | */ 39 | private static final List DT_TYPE_LIST = Arrays.asList( 40 | StockConst.DT_DAY, 41 | StockConst.DT_WEEK, 42 | StockConst.DT_MONTH 43 | ); 44 | 45 | /** 46 | * 获取接口日志 47 | * 48 | * @param dtType 49 | * @return 50 | */ 51 | private String getApiUrl(Integer dtType) { 52 | StringBuilder stringBuilder = new StringBuilder(); 53 | stringBuilder.append(API_URL); 54 | switch (dtType) { 55 | case StockConst.DT_WEEK: 56 | stringBuilder.append("akweekly/"); 57 | break; 58 | case StockConst.DT_MONTH: 59 | stringBuilder.append("akmonthly/"); 60 | break; 61 | default: 62 | stringBuilder.append("akdaily/"); 63 | break; 64 | } 65 | return stringBuilder.toString(); 66 | } 67 | 68 | /** 69 | * 获取股票不同分钟粒度线图 70 | * 71 | * @param stockVo 72 | * @return 73 | */ 74 | public List kLine(StockVo stockVo, Integer dtType) { 75 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode() 76 | || null == dtType || !DT_TYPE_LIST.contains(dtType)) { 77 | return null; 78 | } 79 | try { 80 | String iFengStockCode = iFengStockCode(stockVo); 81 | Map params = new HashMap<>(2); 82 | params.put("code", iFengStockCode); 83 | params.put("type", "last"); 84 | HttpUtil httpUtil = new HttpUtil().setUrl(getApiUrl(dtType)) 85 | .setParams(params) 86 | .setOriCharset(HttpUtil.CHARSET_GBK) 87 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 88 | HttpResponseDto httpResponse = httpUtil.request(); 89 | List iFengKLinePoList = this.handleResponse( 90 | stockVo, httpResponse.getContent() 91 | ); 92 | return iFengKLinePoList; 93 | } catch (IOException e) { 94 | logger.error(stockVo.toString(), e); 95 | } 96 | return null; 97 | } 98 | 99 | /** 100 | * 解析返回数据 101 | * 102 | * @param stockVo 103 | * @param response 104 | * @return 105 | */ 106 | private List handleResponse(StockVo stockVo, String response) { 107 | if (null == stockVo || null == response || response.isEmpty()) { 108 | return null; 109 | } 110 | try { 111 | JSONObject jsonObject = JSON.parseObject(response); 112 | JSONArray recordArr = jsonObject.containsKey(RESPONSE_KEY_RECORD) ? 113 | jsonObject.getJSONArray(RESPONSE_KEY_RECORD) : null; 114 | if (null == recordArr || recordArr.isEmpty()) { 115 | return null; 116 | } 117 | List iFengKLinePoList = null; 118 | for (int i = 0; i < recordArr.size(); i++) { 119 | JSONArray minuteArr = recordArr.getJSONArray(i); 120 | if (null == minuteArr || minuteArr.isEmpty()) { 121 | continue; 122 | } 123 | IFengKLinePo iFengKLinePo = null; 124 | for (int j = 0; j < minuteArr.size(); j++) { 125 | String str = minuteArr.getString(j); 126 | if (null == str || str.isEmpty()) { 127 | continue; 128 | } 129 | if (null == iFengKLinePo) { 130 | iFengKLinePo = new IFengKLinePo(); 131 | } 132 | if (0 == j) { 133 | iFengKLinePo.setDt(str); 134 | } else if (1 == j) { 135 | iFengKLinePo.setOpenPrice(BigDecimalUtil.initPrice(str)); 136 | } else if (2 == j) { 137 | iFengKLinePo.setHighestPrice(BigDecimalUtil.initPrice(str)); 138 | } else if (3 == j) { 139 | iFengKLinePo.setClosePrice(BigDecimalUtil.initPrice(str)); 140 | } else if (4 == j) { 141 | iFengKLinePo.setLowestPrice(BigDecimalUtil.initPrice(str)); 142 | } else if (5 == j) { 143 | iFengKLinePo.setDealMoney(BigDecimalUtil.initPrice(str)); 144 | } else { 145 | break; 146 | } 147 | } 148 | if (null != iFengKLinePo) { 149 | iFengKLinePoList = null == iFengKLinePoList ? 150 | new ArrayList<>() : iFengKLinePoList; 151 | iFengKLinePoList.add(iFengKLinePo); 152 | } 153 | } 154 | return iFengKLinePoList; 155 | } catch (Exception e) { 156 | logger.error(response, e); 157 | } 158 | return null; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengFiveDayMinuteScopeKLineApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.alibaba.fastjson.JSON; 4 | import com.alibaba.fastjson.JSONArray; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.ifeng.IFengFiveDayMinuteScopeKLinePo; 8 | import com.fox.spider.stock.entity.vo.StockVo; 9 | import com.fox.spider.stock.util.BigDecimalUtil; 10 | import com.fox.spider.stock.util.DateUtil; 11 | import com.fox.spider.stock.util.HttpUtil; 12 | import org.slf4j.Logger; 13 | import org.slf4j.LoggerFactory; 14 | import org.springframework.stereotype.Component; 15 | 16 | import java.io.IOException; 17 | import java.util.*; 18 | 19 | /** 20 | * 凤凰网5日分钟线图数据 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/6 16:40 24 | */ 25 | @Component 26 | public class IFengFiveDayMinuteScopeKLineApi extends IFengBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * 接口地址 33 | * https://api.finance.ifeng.com/akmin?scode=sz002475&type=5 34 | */ 35 | private static final String API_URL = "https://api.finance.ifeng.com/akmin"; 36 | /** 37 | * 支持分钟粒度范围类别 38 | */ 39 | private static final List MINUTE_SCOPE_LIST = Arrays.asList(5, 15, 130, 60); 40 | 41 | /** 42 | * 获取股票不同分钟粒度线图 43 | * 44 | * @param stockVo 45 | * @return 46 | */ 47 | public List minuteScopeKLine(StockVo stockVo, Integer scope) { 48 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode() 49 | || null == scope || !MINUTE_SCOPE_LIST.contains(scope)) { 50 | return null; 51 | } 52 | try { 53 | String iFengStockCode = iFengStockCode(stockVo); 54 | Map params = new HashMap<>(2); 55 | params.put("scode", iFengStockCode); 56 | params.put("type", scope); 57 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 58 | .setParams(params) 59 | .setOriCharset(HttpUtil.CHARSET_GBK) 60 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 61 | HttpResponseDto httpResponse = httpUtil.request(); 62 | List iFengFiveDayMinuteScopeKLinePoList = this.handleResponse( 63 | stockVo, httpResponse.getContent() 64 | ); 65 | return iFengFiveDayMinuteScopeKLinePoList; 66 | } catch (IOException e) { 67 | logger.error(stockVo.toString(), e); 68 | } 69 | return null; 70 | } 71 | 72 | /** 73 | * 解析返回数据 74 | * 75 | * @param stockVo 76 | * @param response 77 | * @return 78 | */ 79 | private List handleResponse(StockVo stockVo, String response) { 80 | if (null == stockVo || null == response || response.isEmpty()) { 81 | return null; 82 | } 83 | try { 84 | JSONObject jsonObject = JSON.parseObject(response); 85 | JSONArray recordArr = jsonObject.containsKey(RESPONSE_KEY_RECORD) ? 86 | jsonObject.getJSONArray(RESPONSE_KEY_RECORD) : null; 87 | if (null == recordArr || recordArr.isEmpty()) { 88 | return null; 89 | } 90 | List iFengFiveDayMinuteScopeKLinePoList = null; 91 | for (int i = 0; i < recordArr.size(); i++) { 92 | JSONArray minuteArr = recordArr.getJSONArray(i); 93 | if (null == minuteArr || minuteArr.isEmpty()) { 94 | continue; 95 | } 96 | IFengFiveDayMinuteScopeKLinePo iFengFiveDayMinuteScopeKLinePo = null; 97 | for (int j = 0; j < minuteArr.size(); j++) { 98 | String str = minuteArr.getString(j); 99 | if (null == str || str.isEmpty()) { 100 | continue; 101 | } 102 | if (null == iFengFiveDayMinuteScopeKLinePo) { 103 | iFengFiveDayMinuteScopeKLinePo = new IFengFiveDayMinuteScopeKLinePo(); 104 | } 105 | if (0 == j) { 106 | iFengFiveDayMinuteScopeKLinePo.setDt( 107 | DateUtil.dateStrFormatChange(str, DateUtil.TIME_FORMAT_1, DateUtil.DATE_FORMAT_1) 108 | ); 109 | iFengFiveDayMinuteScopeKLinePo.setTime( 110 | DateUtil.dateStrFormatChange(str, DateUtil.TIME_FORMAT_1, DateUtil.TIME_FORMAT_2) 111 | ); 112 | } else if (1 == j) { 113 | iFengFiveDayMinuteScopeKLinePo.setOpenPrice(BigDecimalUtil.initPrice(str)); 114 | } else if (2 == j) { 115 | iFengFiveDayMinuteScopeKLinePo.setHighestPrice(BigDecimalUtil.initPrice(str)); 116 | } else if (3 == j) { 117 | iFengFiveDayMinuteScopeKLinePo.setClosePrice(BigDecimalUtil.initPrice(str)); 118 | } else if (4 == j) { 119 | iFengFiveDayMinuteScopeKLinePo.setLowestPrice(BigDecimalUtil.initPrice(str)); 120 | } else if (5 == j) { 121 | iFengFiveDayMinuteScopeKLinePo.setDealMoney(BigDecimalUtil.initPrice(str)); 122 | } else { 123 | break; 124 | } 125 | } 126 | if (null != iFengFiveDayMinuteScopeKLinePo) { 127 | iFengFiveDayMinuteScopeKLinePoList = null == iFengFiveDayMinuteScopeKLinePoList ? 128 | new ArrayList<>() : iFengFiveDayMinuteScopeKLinePoList; 129 | iFengFiveDayMinuteScopeKLinePoList.add(iFengFiveDayMinuteScopeKLinePo); 130 | } 131 | } 132 | return iFengFiveDayMinuteScopeKLinePoList; 133 | } catch (Exception e) { 134 | logger.error(response, e); 135 | } 136 | return null; 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaRealtimeDealDetailTimeScopeApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.sina.SinaRealtimeDealDetailTimeScopeDataPo; 8 | import com.fox.spider.stock.entity.po.sina.SinaRealtimeDealDetailTimeScopePo; 9 | import com.fox.spider.stock.entity.vo.StockVo; 10 | import com.fox.spider.stock.util.HttpUtil; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 新浪股票交易明细时间范围接口 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/8 16:16 24 | */ 25 | @Component 26 | public class SinaRealtimeDealDetailTimeScopeApi extends SinaBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * A股接口地址 33 | * https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_Transactions.getAllPageTime?symbol=sh603383 34 | */ 35 | private static final String API_URL = 36 | "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/CN_Transactions.getAllPageTime"; 37 | /** 38 | * 返回数据日期key 39 | */ 40 | private static final String RESPONSE_KEY_DETAIL_DATE = "detailDate"; 41 | /** 42 | * 返回数据页码key 43 | */ 44 | private static final String RESPONSE_KEY_DETAIL_PAGES = "detailPages"; 45 | /** 46 | * 返回数据页码key 47 | */ 48 | private static final String RESPONSE_KEY_DETAIL_PAGE = "page"; 49 | /** 50 | * 返回数据开始时间key 51 | */ 52 | private static final String RESPONSE_KEY_DETAIL_BEGIN_TS = "begin_ts"; 53 | /** 54 | * 返回数据结束时间key 55 | */ 56 | private static final String RESPONSE_KEY_DETAIL_END_TS = "end_ts"; 57 | 58 | /** 59 | * 获取交易明细时间范围 60 | * 61 | * @param stockVo 62 | * @return 63 | */ 64 | public SinaRealtimeDealDetailTimeScopePo dealDetailTimeScope(StockVo stockVo) { 65 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 66 | return null; 67 | } 68 | try { 69 | String sinaStockCode = sinaStockCode(stockVo); 70 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 71 | .setParam("symbol", sinaStockCode) 72 | .setOriCharset(HttpUtil.CHARSET_GBK) 73 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 74 | HttpResponseDto httpResponse = httpUtil.request(); 75 | SinaRealtimeDealDetailTimeScopePo sinaRealtimeDealDetailTimeScopePo = 76 | handleResponse(httpResponse.getContent()); 77 | return sinaRealtimeDealDetailTimeScopePo; 78 | } catch (IOException e) { 79 | logger.error(stockVo.toString(), e); 80 | } 81 | return null; 82 | } 83 | 84 | /** 85 | * 处理返回信息 86 | * 87 | * @param response 88 | * @return 89 | */ 90 | private SinaRealtimeDealDetailTimeScopePo handleResponse(String response) { 91 | if (!(response instanceof String) || response.isEmpty()) { 92 | return null; 93 | } 94 | try{ 95 | JSONObject jsonObject = JSONObject.parseObject(response); 96 | if (null != jsonObject) { 97 | SinaRealtimeDealDetailTimeScopePo sinaRealtimeDealDetailTimeScopePo = 98 | new SinaRealtimeDealDetailTimeScopePo(); 99 | if (jsonObject.containsKey(RESPONSE_KEY_DETAIL_DATE)) { 100 | sinaRealtimeDealDetailTimeScopePo.setDt(jsonObject.getString(RESPONSE_KEY_DETAIL_DATE)); 101 | } 102 | if (jsonObject.containsKey(RESPONSE_KEY_DETAIL_PAGES)) { 103 | JSONArray jsonArray = jsonObject.getJSONArray(RESPONSE_KEY_DETAIL_PAGES); 104 | List sinaRealtimeDealDetailTimeScopeDataPoList = 105 | new ArrayList<>(); 106 | for (int i = 0; i < jsonArray.size(); i++) { 107 | JSONObject pageJO = jsonArray.getJSONObject(i); 108 | if (null != pageJO) { 109 | SinaRealtimeDealDetailTimeScopeDataPo sinaRealtimeDealDetailTimeScopeDataPo = 110 | new SinaRealtimeDealDetailTimeScopeDataPo(); 111 | if (pageJO.containsKey(RESPONSE_KEY_DETAIL_PAGE)) { 112 | sinaRealtimeDealDetailTimeScopeDataPo.setPageNum( 113 | pageJO.getInteger(RESPONSE_KEY_DETAIL_PAGE) 114 | ); 115 | } 116 | if (pageJO.containsKey(RESPONSE_KEY_DETAIL_BEGIN_TS)) { 117 | sinaRealtimeDealDetailTimeScopeDataPo.setStartTime( 118 | pageJO.getString(RESPONSE_KEY_DETAIL_BEGIN_TS) 119 | ); 120 | } 121 | if (pageJO.containsKey(RESPONSE_KEY_DETAIL_END_TS)) { 122 | sinaRealtimeDealDetailTimeScopeDataPo.setEndTime( 123 | pageJO.getString(RESPONSE_KEY_DETAIL_END_TS) 124 | ); 125 | } 126 | sinaRealtimeDealDetailTimeScopeDataPoList.add(sinaRealtimeDealDetailTimeScopeDataPo); 127 | } 128 | } 129 | if (!sinaRealtimeDealDetailTimeScopeDataPoList.isEmpty()) { 130 | sinaRealtimeDealDetailTimeScopePo.setTimeScopeList(sinaRealtimeDealDetailTimeScopeDataPoList); 131 | } 132 | } 133 | return sinaRealtimeDealDetailTimeScopePo; 134 | } 135 | } catch (JSONException e) { 136 | logger.error(response, e); 137 | } 138 | return null; 139 | } 140 | } 141 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/sina/SinaRealtimeDealDetailApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.sina; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.po.sina.SinaRealtimeDealDetailPo; 5 | import com.fox.spider.stock.entity.vo.StockVo; 6 | import com.fox.spider.stock.util.BigDecimalUtil; 7 | import org.jsoup.Jsoup; 8 | import org.jsoup.nodes.Document; 9 | import org.jsoup.nodes.Element; 10 | import org.jsoup.select.Elements; 11 | import org.slf4j.Logger; 12 | import org.slf4j.LoggerFactory; 13 | import org.springframework.stereotype.Component; 14 | 15 | import java.io.IOException; 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | 19 | /** 20 | * 新浪网股票最新交易日交易明细 21 | * 22 | * @author lusongsong 23 | * @date 2021/1/8 16:51 24 | */ 25 | @Component 26 | public class SinaRealtimeDealDetailApi extends SinaBaseApi { 27 | /** 28 | * 日志 29 | */ 30 | private Logger logger = LoggerFactory.getLogger(getClass()); 31 | /** 32 | * A股接口地址 33 | * https://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php?symbol=sh603383&page=36 34 | */ 35 | private static final String API_URL = 36 | "https://vip.stock.finance.sina.com.cn/quotes_service/view/vMS_tradedetail.php?symbol="; 37 | 38 | /** 39 | * 获取页面地址 40 | * 41 | * @param stockVo 42 | * @param page 43 | * @return 44 | */ 45 | private String getApiUrl(StockVo stockVo, Integer page) { 46 | StringBuilder stringBuilder = new StringBuilder(); 47 | stringBuilder.append(API_URL); 48 | stringBuilder.append((String) sinaStockCode(stockVo)); 49 | stringBuilder.append("&page="); 50 | stringBuilder.append(page); 51 | return stringBuilder.toString(); 52 | } 53 | 54 | /** 55 | * 获取交易类型 56 | * 57 | * @param text 58 | * @return 59 | */ 60 | private int getDealType(String text) { 61 | switch (text) { 62 | case "买盘": 63 | return StockConst.DEAL_BUY; 64 | case "卖盘": 65 | return StockConst.DEAL_SELL; 66 | case "其他": 67 | case "中性盘": 68 | return StockConst.DEAL_FLAT; 69 | default: 70 | return StockConst.DEAL_UNKNOWN; 71 | } 72 | } 73 | 74 | /** 75 | * 去除百分号 76 | * 77 | * @param text 78 | * @return 79 | */ 80 | private String clearText(String text) { 81 | return text.replace("%", "").replace(",", ""); 82 | } 83 | 84 | /** 85 | * 获取交易明细数据数据 86 | * 87 | * @param stockVo 88 | * @return 89 | */ 90 | public List dealDetail(StockVo stockVo, Integer page) { 91 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode() 92 | || null == page || page < 0) { 93 | return null; 94 | } 95 | try { 96 | Document document = Jsoup.connect(getApiUrl(stockVo, page)).get(); 97 | Element tableElement = document.getElementById("datatbl"); 98 | Elements tbodyElements = tableElement.getElementsByTag("tbody"); 99 | Element tbodyElement = tbodyElements.first(); 100 | return handleResponse(tbodyElement); 101 | } catch (IOException e) { 102 | logger.error(stockVo.toString() + page.toString(), e); 103 | } 104 | return null; 105 | } 106 | 107 | /** 108 | * 处理返回数据 109 | * 110 | * @param tbodyElement 111 | * @return 112 | */ 113 | private List handleResponse(Element tbodyElement) { 114 | List sinaRealtimeDealDetailPoList = null; 115 | if (null != tbodyElement) { 116 | Elements trElements = tbodyElement.getElementsByTag("tr"); 117 | if (null != trElements && !trElements.isEmpty()) { 118 | for (Element trElement : trElements) { 119 | if (null != trElement) { 120 | Elements tdElements = trElement.children(); 121 | SinaRealtimeDealDetailPo sinaRealtimeDealDetailPo = handleRow(tdElements); 122 | if (null != sinaRealtimeDealDetailPo) { 123 | sinaRealtimeDealDetailPoList = null == sinaRealtimeDealDetailPoList ? 124 | new ArrayList<>() : sinaRealtimeDealDetailPoList; 125 | sinaRealtimeDealDetailPoList.add(sinaRealtimeDealDetailPo); 126 | } 127 | } 128 | } 129 | } 130 | } 131 | return sinaRealtimeDealDetailPoList; 132 | } 133 | 134 | /** 135 | * 处理单条交易明细 136 | * 137 | * @param tdElements 138 | * @return 139 | */ 140 | private SinaRealtimeDealDetailPo handleRow(Elements tdElements) { 141 | SinaRealtimeDealDetailPo sinaRealtimeDealDetailPo = null; 142 | if (null != tdElements && !tdElements.isEmpty()) { 143 | sinaRealtimeDealDetailPo = new SinaRealtimeDealDetailPo(); 144 | for (int i = 0; i < tdElements.size(); i++) { 145 | Element tdElement = tdElements.get(i); 146 | String text = tdElement.text(); 147 | text = clearText(text); 148 | if (0 == i) { 149 | sinaRealtimeDealDetailPo.setTime(text); 150 | } else if (1 == i) { 151 | sinaRealtimeDealDetailPo.setPrice(BigDecimalUtil.initPrice(text)); 152 | } else if (2 == i) { 153 | sinaRealtimeDealDetailPo.setUptickRate(BigDecimalUtil.initRate(text)); 154 | } else if (3 == i) { 155 | try { 156 | sinaRealtimeDealDetailPo.setUptickPrice(BigDecimalUtil.initPrice(text)); 157 | } catch (NumberFormatException e) { 158 | sinaRealtimeDealDetailPo.setUptickPrice(BigDecimalUtil.initPrice("0")); 159 | } 160 | } else if (4 == i) { 161 | sinaRealtimeDealDetailPo.setDealNum(BigDecimalUtil.initLong(text)); 162 | } else if (5 == i) { 163 | sinaRealtimeDealDetailPo.setDealMoney(BigDecimalUtil.initPrice(text)); 164 | } else if (6 == i) { 165 | sinaRealtimeDealDetailPo.setDealType(getDealType(text)); 166 | } 167 | } 168 | } 169 | return sinaRealtimeDealDetailPo; 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/ifeng/IFengRealtimeDealDetailApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.ifeng; 2 | 3 | import com.fox.spider.stock.constant.StockConst; 4 | import com.fox.spider.stock.entity.po.ifeng.IFengRealtimeDealDetailDataPo; 5 | import com.fox.spider.stock.entity.po.ifeng.IFengRealtimeDealDetailPo; 6 | import com.fox.spider.stock.entity.vo.StockVo; 7 | import com.fox.spider.stock.util.BigDecimalUtil; 8 | import com.fox.spider.stock.util.DateUtil; 9 | import org.jsoup.Jsoup; 10 | import org.jsoup.nodes.Document; 11 | import org.jsoup.nodes.Element; 12 | import org.jsoup.select.Elements; 13 | import org.slf4j.Logger; 14 | import org.slf4j.LoggerFactory; 15 | import org.springframework.stereotype.Component; 16 | 17 | import java.io.IOException; 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | /** 22 | * 凤凰网实时交易详情 23 | * 24 | * @author lusongsong 25 | * @date 2021/1/7 17:22 26 | */ 27 | @Component 28 | public class IFengRealtimeDealDetailApi extends IFengBaseApi { 29 | /** 30 | * 日志 31 | */ 32 | private Logger logger = LoggerFactory.getLogger(getClass()); 33 | /** 34 | * 接口地址 35 | * http://app.finance.ifeng.com/data/stock/stock_item3.php?code=sz002475 36 | */ 37 | private static final String API_URL = "http://app.finance.ifeng.com/data/stock/stock_item3.php?code="; 38 | 39 | /** 40 | * 获取交易类型 41 | * 42 | * @param text 43 | * @return 44 | */ 45 | private int getDealType(String text) { 46 | switch (text) { 47 | case "买盘": 48 | return StockConst.DEAL_BUY; 49 | case "卖盘": 50 | return StockConst.DEAL_SELL; 51 | case "其他": 52 | case "中性盘": 53 | return StockConst.DEAL_FLAT; 54 | default: 55 | return StockConst.DEAL_UNKNOWN; 56 | } 57 | } 58 | 59 | /** 60 | * 获取大单交易数据 61 | * 62 | * @param stockVo 63 | * @return 64 | */ 65 | public IFengRealtimeDealDetailPo dealDetail(StockVo stockVo) { 66 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 67 | return null; 68 | } 69 | try { 70 | String iFengStockCode = iFengStockCode(stockVo); 71 | Document document = Jsoup.connect(API_URL + iFengStockCode).get(); 72 | Elements pageElements = document.select("a[title=尾页]"); 73 | Element pageElement = pageElements.first(); 74 | List iFengRealtimeDealDetailDataPoList = handleResponse(document); 75 | if (null != pageElement && null != iFengRealtimeDealDetailDataPoList) { 76 | IFengRealtimeDealDetailPo iFengRealtimeDealDetailPo = new IFengRealtimeDealDetailPo(); 77 | iFengRealtimeDealDetailPo.setTotalPageNum(Integer.valueOf(pageElement.text())); 78 | iFengRealtimeDealDetailPo.setDetailInfoList(iFengRealtimeDealDetailDataPoList); 79 | return iFengRealtimeDealDetailPo; 80 | } 81 | } catch (NumberFormatException e) { 82 | logger.error(stockVo.toString(), e); 83 | } catch (IOException e) { 84 | logger.error(stockVo.toString(), e); 85 | } 86 | return null; 87 | } 88 | 89 | /** 90 | * 处理返回数据 91 | * 92 | * @param document 93 | * @return 94 | */ 95 | private List handleResponse(Document document) { 96 | List iFengRealtimeDealDetailDataPoList = null; 97 | if (null != document) { 98 | Elements tableElements = document.body().getElementsByTag("table"); 99 | if (null != tableElements && !tableElements.isEmpty()) { 100 | Element tableElement = tableElements.first(); 101 | Elements trElements = tableElement.getElementsByTag("tr"); 102 | if (null != trElements && !trElements.isEmpty()) { 103 | for (Element trElement : trElements) { 104 | if (null != trElement) { 105 | Elements tdElements = trElement.children(); 106 | IFengRealtimeDealDetailDataPo iFengRealtimeDealDetailDataPo = handleRow(tdElements); 107 | if (null != iFengRealtimeDealDetailDataPo) { 108 | iFengRealtimeDealDetailDataPoList = null == iFengRealtimeDealDetailDataPoList ? 109 | new ArrayList<>() : iFengRealtimeDealDetailDataPoList; 110 | iFengRealtimeDealDetailDataPoList.add(iFengRealtimeDealDetailDataPo); 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | return iFengRealtimeDealDetailDataPoList; 118 | } 119 | 120 | /** 121 | * 处理单条大单交易 122 | * 123 | * @param tdElements 124 | * @return 125 | */ 126 | private IFengRealtimeDealDetailDataPo handleRow(Elements tdElements) { 127 | IFengRealtimeDealDetailDataPo iFengRealtimeDealDetailDataPo = null; 128 | if (null != tdElements && !tdElements.isEmpty()) { 129 | for (int i = 0; i < tdElements.size(); i++) { 130 | Element tdElement = tdElements.get(i); 131 | if (tdElement.getElementsByTag("th").isEmpty()) { 132 | iFengRealtimeDealDetailDataPo = null == iFengRealtimeDealDetailDataPo ? 133 | new IFengRealtimeDealDetailDataPo() : iFengRealtimeDealDetailDataPo; 134 | String text = tdElement.text(); 135 | if (0 == i) { 136 | iFengRealtimeDealDetailDataPo.setDt( 137 | DateUtil.dateStrFormatChange(text, DateUtil.TIME_FORMAT_1, DateUtil.DATE_FORMAT_1) 138 | ); 139 | iFengRealtimeDealDetailDataPo.setTime( 140 | DateUtil.dateStrFormatChange(text, DateUtil.TIME_FORMAT_1, DateUtil.TIME_FORMAT_2) 141 | ); 142 | } else if (1 == i) { 143 | iFengRealtimeDealDetailDataPo.setDealType(getDealType(text)); 144 | } else if (2 == i) { 145 | iFengRealtimeDealDetailDataPo.setPrice(BigDecimalUtil.initPrice(text)); 146 | } else if (3 == i) { 147 | iFengRealtimeDealDetailDataPo.setDealNum(BigDecimalUtil.initLong(text)); 148 | } else if (4 == i) { 149 | iFengRealtimeDealDetailDataPo.setDealMoney(BigDecimalUtil.initPrice(text)); 150 | } 151 | } 152 | } 153 | } 154 | return iFengRealtimeDealDetailDataPo; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/com/fox/spider/stock/api/tencent/TencentRealtimeMinuteKLineApi.java: -------------------------------------------------------------------------------- 1 | package com.fox.spider.stock.api.tencent; 2 | 3 | import com.alibaba.fastjson.JSONArray; 4 | import com.alibaba.fastjson.JSONException; 5 | import com.alibaba.fastjson.JSONObject; 6 | import com.fox.spider.stock.entity.dto.http.HttpResponseDto; 7 | import com.fox.spider.stock.entity.po.tencent.TencentRealtimeDealInfoPo; 8 | import com.fox.spider.stock.entity.po.tencent.TencentRealtimeMinuteKLinePo; 9 | import com.fox.spider.stock.entity.po.tencent.TencentRealtimeMinuteNodeDataPo; 10 | import com.fox.spider.stock.entity.vo.StockVo; 11 | import com.fox.spider.stock.util.BigDecimalUtil; 12 | import com.fox.spider.stock.util.DateUtil; 13 | import com.fox.spider.stock.util.HttpUtil; 14 | import org.slf4j.Logger; 15 | import org.slf4j.LoggerFactory; 16 | import org.springframework.stereotype.Component; 17 | 18 | import java.io.IOException; 19 | import java.util.HashMap; 20 | import java.util.List; 21 | import java.util.Map; 22 | 23 | /** 24 | * 腾讯股票实时分钟线图 25 | * 26 | * @author lusongsong 27 | * @date 2020/12/25 14:55 28 | */ 29 | @Component 30 | public class TencentRealtimeMinuteKLineApi extends TencentKLineBaseApi { 31 | /** 32 | * 日志 33 | */ 34 | private Logger logger = LoggerFactory.getLogger(getClass()); 35 | /** 36 | * 接口地址 37 | * https://web.ifzq.gtimg.cn/appstock/app/minute/query?_var=min_data&code=sz000002 38 | */ 39 | private static final String API_URL = "https://web.ifzq.gtimg.cn/appstock/app/minute/query"; 40 | /** 41 | * _var参数值 42 | */ 43 | private static String PARAM_VAR = "min_data"; 44 | 45 | /** 46 | * 获取实时交易分钟线图数据 47 | * 48 | * @param stockVo 49 | * @return 50 | */ 51 | public TencentRealtimeMinuteKLinePo realtimeMinuteKLine(StockVo stockVo) { 52 | if (null == stockVo || null == stockVo.getStockMarket() || null == stockVo.getStockCode()) { 53 | return null; 54 | } 55 | try { 56 | String tencnetStockCode = TencentBaseApi.tencentStockCode(stockVo); 57 | if (null == tencnetStockCode && tencnetStockCode.isEmpty()) { 58 | return null; 59 | } 60 | Map params = new HashMap<>(2); 61 | params.put("_var", PARAM_VAR); 62 | params.put("code", tencnetStockCode); 63 | HttpUtil httpUtil = new HttpUtil().setUrl(API_URL) 64 | .setParams(params) 65 | .setOriCharset(HttpUtil.CHARSET_GBK) 66 | .setErrorOriCharset(HttpUtil.CHARSET_UTF8); 67 | HttpResponseDto httpResponse = httpUtil.request(); 68 | TencentRealtimeMinuteKLinePo tencentRealtimeMinuteKLinePo = this.handleResponse( 69 | stockVo, httpResponse.getContent() 70 | ); 71 | if (null != tencentRealtimeMinuteKLinePo) { 72 | tencentRealtimeMinuteKLinePo.setStockMarket(stockVo.getStockMarket()); 73 | tencentRealtimeMinuteKLinePo.setStockCode(stockVo.getStockCode()); 74 | } 75 | return tencentRealtimeMinuteKLinePo; 76 | } catch (IOException e) { 77 | logger.error(stockVo.toString(), e); 78 | } 79 | return null; 80 | } 81 | 82 | /** 83 | * 解析返回数据 84 | * 85 | * @param stockVo 86 | * @param response 87 | * @return 88 | */ 89 | private TencentRealtimeMinuteKLinePo handleResponse(StockVo stockVo, String response) { 90 | if (null == stockVo || null == response || response.isEmpty()) { 91 | return null; 92 | } 93 | try { 94 | String stockCode = TencentBaseApi.tencentStockCode(stockVo); 95 | JSONObject jsonObject = getResponseJSONObject(stockVo, response); 96 | JSONObject dealInfoObject = jsonObject.containsKey(RESPONSE_KEY_QT) ? 97 | jsonObject.getJSONObject(RESPONSE_KEY_QT) : null; 98 | TencentRealtimeMinuteKLinePo tencentRealtimeMinuteKLinePo = new TencentRealtimeMinuteKLinePo(); 99 | if (null != dealInfoObject && dealInfoObject.containsKey(stockCode)) { 100 | JSONArray dealInfoArr = dealInfoObject.getJSONArray(stockCode); 101 | TencentRealtimeDealInfoPo tencentRealtimeDealInfoPo = 102 | TencentRealtimeDealInfoApi.getDealInfo(stockVo, dealInfoArr.toArray(new String[]{})); 103 | if (null != tencentRealtimeDealInfoPo) { 104 | tencentRealtimeMinuteKLinePo.setRealtimeDealInfo(tencentRealtimeDealInfoPo); 105 | tencentRealtimeMinuteKLinePo.setStockName( 106 | tencentRealtimeDealInfoPo.getStockName() 107 | ); 108 | tencentRealtimeMinuteKLinePo.setPreClosePrice( 109 | tencentRealtimeDealInfoPo.getPreClosePrice() 110 | ); 111 | tencentRealtimeMinuteKLinePo.setDealNum( 112 | tencentRealtimeDealInfoPo.getDealNum() 113 | ); 114 | } 115 | } 116 | JSONObject minKLineObject = jsonObject.containsKey(RESPONSE_KEY_DATA) ? 117 | jsonObject.getJSONObject(RESPONSE_KEY_DATA) : null; 118 | if (null != minKLineObject) { 119 | if (minKLineObject.containsKey(RESPONSE_KEY_DATE)) { 120 | tencentRealtimeMinuteKLinePo.setDt( 121 | DateUtil.dateStrFormatChange( 122 | minKLineObject.getString(RESPONSE_KEY_DATE), 123 | DateUtil.DATE_FORMAT_2, 124 | DateUtil.DATE_FORMAT_1 125 | ) 126 | ); 127 | } 128 | if (minKLineObject.containsKey(RESPONSE_KEY_DATA)) { 129 | JSONArray minKLineArr = minKLineObject.getJSONArray(RESPONSE_KEY_DATA); 130 | if (null != minKLineArr && !minKLineArr.isEmpty()) { 131 | List tencentRealtimeMinuteNodeDataPoList = 132 | handleDayMinArr(stockVo, minKLineArr); 133 | if (null != tencentRealtimeMinuteNodeDataPoList 134 | && !tencentRealtimeMinuteNodeDataPoList.isEmpty()) { 135 | tencentRealtimeMinuteKLinePo.setNodeCount(tencentRealtimeMinuteNodeDataPoList.size()); 136 | tencentRealtimeMinuteKLinePo.setKlineData(tencentRealtimeMinuteNodeDataPoList); 137 | } 138 | } 139 | } 140 | } 141 | return tencentRealtimeMinuteKLinePo; 142 | } catch (JSONException e) { 143 | logger.error(response, e); 144 | } 145 | return null; 146 | } 147 | } 148 | --------------------------------------------------------------------------------