跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava算法

Java 量化实战:股票详细信息实时获取与多数据源架构

基于 SpringBoot 实现股票详细信息实时获取模块。通过定义 StockShowInfoDto 统一数据模型,对接财联社与腾讯两大公开数据源。采用主备切换架构保障稳定性,财联社为主,腾讯为备。核心涵盖请求构建、反爬处理、GBK 编码解析及异常降级策略。代码复用历史数据爬取基础,确保系统一致性,适合 Java 量化开发参考。

2177283801发布于 2026/3/24更新于 2026/7/2836 浏览
Java 量化实战:股票详细信息实时获取与多数据源架构

在前期基础中,我们完成了自选股票维护功能。但对量化交易者而言,仅维护列表不够,还需实时掌握单只股票的关键信息,如当前价格、涨跌幅度、成交量等,这些是判断短期走势的核心依据。

本文聚焦股票详细信息获取模块,基于 SpringBoot 技术栈,实现两大核心目标:一是定义统一的股票详情数据模型(StockShowInfoDto),兼容不同数据源的字段映射;二是对接财联社、腾讯两大公开数据源,实现股票详情信息的实时爬取、解析与封装。同时复用历史数据爬取基础代码,保证系统一致性。

一、核心需求与数据模型设计

1.1 核心需求边界

股票详细信息获取的核心诉求是实时性、完整性与兼容性。结合量化交易场景,明确需求边界如下:

  • 数据完整性:覆盖基础信息(代码、名称)、行情数据(开盘/收盘/最高/最低价)、交易数据(成交量、金额)、估值数据(市盈率)及辅助判断数据(涨跌幅、涨停状态);
  • 多数据源兼容:对接财联社、腾讯两大数据源,支持自动切换,避免单一数据源失效;
  • 实时性保障:通过 HTTP 请求实时爬取,确保获取最新行情;
  • 异常兼容:爬取失败时返回 null 并记录日志,支持降级处理。
1.2 核心数据模型:StockShowInfoDto

为统一不同数据源的返回格式,定义 StockShowInfoDto 作为标准输出模型。通过自定义 getter 方法实现部分字段的自动计算(如涨停状态、涨跌幅度百分比转换)。

@Data
@Schema(description = "股票展示信息")
public class StockShowInfoDto implements Serializable {
    /** 股票的代码(如 001318) */
    @Schema(description = "股票的代码")
    private String code;

    /** 股票的名称(如三峡能源) */
    @Schema(description = "股票的名称")
    private String name;

    /** 当前查询日期 */
    @Schema(description = "日期")
    private String currDate;

    /** 股票的全代码(如 sz001318、sh600000) */
    @Schema(description = "股票的全代码")
    private String fullCode;

    /** 交易所类型(0-未知/1-深交所/2-上交所) */
    @Schema(description = "交易所类型")
    private Integer exchange;

    /** 行情日期(当日) */
    @Schema(description = "当前天")
    private String date;

    /** 开盘价 */
    @Schema(description = "开盘价")
    private BigDecimal openingPrice;

    
    
     BigDecimal yesClosingPrice;

    
    
     BigDecimal highestPrice;

    
    
     BigDecimal lowestPrice;

    
    
     BigDecimal closingPrice;

    
    
     BigDecimal nowPrice;

    
    
      tradingVolume;

    
    
     BigDecimal tradingValue;

    
    
     BigDecimal amplitude;

    
    
     String amplitudeProportion;

    
    
     BigDecimal changingProportion;

    
    
     BigDecimal than;

    
    
     BigDecimal peRatio;

    
    
        ;

    
    
     Double amplitudeProportionDouble;

    
    
     String webUrl;

    
     Integer  {
         StockUtil.isZt(.code, .name, .amplitudeProportion) ?  : ;
    }

    
     Double  {
         (StrUtil.isBlank(amplitudeProportion)) {
             ;
        }
           amplitudeProportion.replace(, );
         Double.parseDouble(substring);
    }
}
/** 昨天的收盘价 */
@Schema(description = "昨天的收盘价")
private
/** 最高价格 */
@Schema(description = "最高价格")
private
/** 最低价格 */
@Schema(description = "最低价格")
private
/** 收盘价(盘后有效,盘中取当前价) */
@Schema(description = "收盘价")
private
/** 当前的价格(盘中实时价格) */
@Schema(description = "当前的价格")
private
/** 成交量 (股) */
@Schema(description = "成交量 (股)")
private
long
/** 成交量金额(元) */
@Schema(description = "成交量金额")
private
/** 涨跌幅度(当前价 - 昨日收盘价) */
@Schema(description = "涨跌幅度")
private
/** 涨跌幅度百分比(带%符号,如 +2.35%) */
@Schema(description = "涨跌幅度百分比")
private
/** 换手率(%) */
@Schema(description = "换手率")
private
/** 量比 */
@Schema(description = "量比")
private
/** 市盈率(TTM) */
@Schema(description = "市盈率")
private
/** 是否涨停(1-涨停/0-不涨停,自动计算) */
@Schema(description = "是否涨停 1 为涨停 0 为不涨停")
private
Integer
zt
=
0
/** 涨跌幅度百分比(double 形式,用于计算) */
@Schema(description = "涨幅 double 形式")
private
/** 数据源网页地址(辅助信息) */
@Schema(description = "webUrl 地址信息")
private
/** * 自动计算是否涨停:调用 StockUtil 工具类判断 * 核心逻辑:根据股票代码(区分主板/创业板/科创板)、当前涨幅判断 */
public
getZt
()
return
this
this
this
1
0
/** * 自动转换涨跌幅度百分比为 double:去除%符号,转为数值型 * 示例:"2.35%" → 2.35,空值返回 0.0 */
public
getAmplitudeProportionDouble
()
if
return
0.0d
String
substring
=
"%"
""
return

关键设计亮点在于自动计算字段,通过自定义 getter 方法实现 zt 和 amplitudeProportionDouble 的自动计算,无需上层代码处理。同时兼顾不同数据源的字段差异,通过 DTO 统一封装,屏蔽底层差异。

二、核心设计:多数据源架构与流程

为避免单一数据源失效导致功能不可用,设计主备数据源架构:以财联社作为主数据源(数据字段更完整),腾讯作为备用数据源(接口稳定性高)。核心流程遵循参数校验、构建请求、发送 HTTP 请求、解析响应数据、DTO 封装、自动计算字段。

三、核心实现:多数据源爬取与封装

下面拆解财联社(主数据源)和腾讯(备用数据源)的完整实现逻辑。

3.1 主数据源:财联社股票详情爬取实现

财联社提供公开的股票详情接口,返回 JSON 格式数据。需依赖 HTTP 工具类发送 GET 请求、JSON 工具类解析响应数据。

@Service
public class StockDetailServiceImpl implements StockDetailService {

    @Override
    public StockShowInfoDto getByCode(String fullCode) {
        // 1. 参数校验:全代码不能为空
        if (StrUtil.isBlank(fullCode)) {
            log.error("财联社爬取股票详情失败:全代码为空");
            return null;
        }
        try {
            // 2. 构建请求 URL:通过 MessageFormat 格式化占位符
            String url = MessageFormat.format(
                "https://x-quote.cls.cn/quote/stock/basic?secu_code={0}&fields=open_px,av_px,high_px,low_px,change,change_px,down_price,change_3,change_5,qrr,entrust_rate,tr,amp,TotalShares,mc,NetAssetPS,NonRestrictedShares,cmc,business_amount,business_balance,pe,ttm_pe,pb,secu_name,secu_code,trade_status,secu_type,preclose_px,up_price,last_px&app=CailianpressWeb&os=web&sv=8.4.6&sign=9f8797a1f4de66c2370f7a03990d2737",
                fullCode
            );
            // 3. 构建请求头:模拟浏览器请求,避免被反爬
            Map<String, String> headerMap = buildDjrHeaderMap();
            // 4. 发送 HTTP GET 请求
            String content = HttpUtil.sendGet(HttpClientConfig.proxyNoUseCloseableHttpClient(), url, headerMap);
            // 5. 解析响应数据
            JSONObject jsonObject = JSONUtil.parseObj(content);
            JSONObject data = jsonObject.getJSONObject("data");
            if (data == null) {
                log.error("财联社爬取股票详情失败:响应数据中 data 节点为空,fullCode={}", fullCode);
                return null;
            }

            // 6. DTO 封装
            StockShowInfoDto stockShowInfoDto = new StockShowInfoDto();
            stockShowInfoDto.setCode(StrUtil.subSufByLength(fullCode, 6));
            stockShowInfoDto.setName(data.getStr("secu_name"));
            stockShowInfoDto.setCurrDate(DateUtil.now());
            stockShowInfoDto.setFullCode(fullCode);
            stockShowInfoDto.setDate(DateUtil.now());
            stockShowInfoDto.setWebUrl("Data Source Link");

            // 行情数据封装
            stockShowInfoDto.setOpeningPrice(data.getBigDecimal("open_px"));
            stockShowInfoDto.setYesClosingPrice(data.getBigDecimal("preclose_px"));
            stockShowInfoDto.setHighestPrice(data.getBigDecimal("high_px"));
            stockShowInfoDto.setLowestPrice(data.getBigDecimal("low_px"));
            stockShowInfoDto.setClosingPrice(data.getBigDecimal("last_px"));
            stockShowInfoDto.setNowPrice(data.getBigDecimal("last_px"));

            // 交易数据封装
            stockShowInfoDto.setTradingVolume(data.getLong("business_amount"));
            stockShowInfoDto.setTradingValue(data.getBigDecimal("business_balance"));
            stockShowInfoDto.setAmplitude(data.getBigDecimal("change_px"));
            stockShowInfoDto.setAmplitudeProportion(BigDecimalUtil.mul100(data.getBigDecimal("change")));

            // 估值与辅助数据封装
            stockShowInfoDto.setChangingProportion(BigDecimalUtil.mul100B(data.getBigDecimal("tr")));
            stockShowInfoDto.setThan(BigDecimalUtil.mul100B(data.getBigDecimal("qrr")));
            stockShowInfoDto.setPeRatio(data.getBigDecimal("ttm_pe"));

            // 自动计算涨停状态
            stockShowInfoDto.setZt(stockShowInfoDto.getZt());
            return stockShowInfoDto;
        } catch (Exception e) {
            log.error("财联社爬取股票详情失败,fullCode={}", fullCode, e);
            return null;
        }
    }

    private Map<String, String> buildDjrHeaderMap() {
        Map<String, String> headerMap = new HashMap<>();
        headerMap.put("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36");
        headerMap.put("Referer", "https://www.cls.cn/");
        headerMap.put("Accept", "application/json, text/plain, */*");
        return headerMap;
    }

    // ... 其他方法见下方合并
}

关键注意点:必须模拟浏览器请求头,否则接口会拒绝返回数据。全代码处理需注意截取后 6 位作为纯代码。数值计算使用 BigDecimalUtil 工具类避免浮点数精度丢失。

3.2 备用数据源:腾讯股票详情爬取实现

腾讯股票接口返回特殊格式字符串,需自定义解析逻辑。该接口稳定性高,适合作为备用数据源。可复用历史数据爬取的基础方法。

    @Resource
    private DefaultProperties defaultProperties;

    @Resource
    private DailyTradingInfoParse dailyTradingInfoParse;

    @Override
    public StockShowInfoDto getNowInfo(String fullCode) {
        if (StrUtil.isBlank(fullCode)) {
            log.error("腾讯爬取股票详情失败:全代码为空");
            return null;
        }
        try {
            // 复用基础方法:爬取腾讯股票当前行情数据
            List<TxStockHistoryInfo> txStockHistoryInfos = parseTxMoneyYesHistory(Collections.singletonList(fullCode), DateTime.now());
            if (CollUtil.isEmpty(txStockHistoryInfos)) {
                log.error("腾讯爬取股票详情失败:解析后数据列表为空,fullCode={}", fullCode);
                return null;
            }

            TxStockHistoryInfo txStockHistoryInfo = txStockHistoryInfos.get(0);
            StockShowInfoDto stockShowInfoDto = new StockShowInfoDto();

            // 基础信息封装
            stockShowInfoDto.setCode(txStockHistoryInfo.getCode());
            stockShowInfoDto.setName(txStockHistoryInfo.getName());
            stockShowInfoDto.setFullCode(fullCode);
            stockShowInfoDto.setExchange(0);
            stockShowInfoDto.setDate(DateUtil.now());

            // 行情数据封装
            stockShowInfoDto.setOpeningPrice(txStockHistoryInfo.getOpeningPrice());
            stockShowInfoDto.setYesClosingPrice(txStockHistoryInfo.getYesClosingPrice());
            stockShowInfoDto.setHighestPrice(txStockHistoryInfo.getHighestPrice());
            stockShowInfoDto.setLowestPrice(txStockHistoryInfo.getLowestPrice());
            stockShowInfoDto.setClosingPrice(txStockHistoryInfo.getClosingPrice());
            stockShowInfoDto.setNowPrice(txStockHistoryInfo.getNowPrice());

            // 交易数据封装
            stockShowInfoDto.setTradingVolume(txStockHistoryInfo.getTradingVolume());
            stockShowInfoDto.setTradingValue(txStockHistoryInfo.getTradingValue());
            stockShowInfoDto.setAmplitude(txStockHistoryInfo.getAmplitude());
            stockShowInfoDto.setAmplitudeProportion(BigDecimalUtil.toShowString2(txStockHistoryInfo.getAmplitudeProportion()));
            stockShowInfoDto.setChangingProportion(txStockHistoryInfo.getChangingProportion());
            stockShowInfoDto.setThan(txStockHistoryInfo.getThan());
            stockShowInfoDto.setPeRatio(txStockHistoryInfo.getDynamicPriceRatio());

            // 涨停状态:腾讯数据未直接提供,暂设为 0
            stockShowInfoDto.setZt(0);
            return stockShowInfoDto;
        } catch (Exception e) {
            log.error("腾讯爬取股票详情失败,fullCode={}", fullCode, e);
            return null;
        }
    }

    @Override
    public List<TxStockHistoryInfo> parseTxMoneyYesHistory(List<String> codeList, DateTime beforeLastWorking) {
        String qParam = StrUtil.join(",", codeList);
        String url = MessageFormat.format(defaultProperties.getTxMoneyHistoryUrl(), qParam);
        try {
            Map<String, String> header = new HashMap<>();
            header.put("Referer", "http://qt.gtimg.cn");
            // 腾讯接口响应编码为 GBK
            String content = HttpUtil.sendGet(HttpClientConfig.proxyNoUseCloseableHttpClient(), url, header, "gbk");
            return dailyTradingInfoParse.parseTxMoneyHistory(content, codeList, beforeLastWorking);
        } catch (Exception e) {
            log.error("parseTxMoneyYesHistory 获取股票{}当前信息失败", qParam, e);
            return null;
        }
    }

关键注意点:响应编码需指定为 GBK,否则会出现中文乱码。腾讯接口返回特殊格式字符串,需通过专用解析工具类自定义解析逻辑。

3.3 数据源切换策略实现

为实现主备数据源自动切换,新增数据源选择器方法。优先调用财联社接口,若返回 null 则自动调用腾讯接口;若均失败,返回 null 并记录日志。

    @Override
    public StockShowInfoDto getStockDetail(String fullCode) {
        // 1. 优先调用主数据源(财联社)
        StockShowInfoDto mainSourceResult = getByCode(fullCode);
        if (mainSourceResult != null) {
            return mainSourceResult;
        }
        // 2. 主数据源失败,切换备用数据源(腾讯)
        log.warn("财联社爬取失败,切换腾讯数据源,fullCode={}", fullCode);
        StockShowInfoDto backupSourceResult = getNowInfo(fullCode);
        if (backupSourceResult != null) {
            return backupSourceResult;
        }
        // 3. 均失败,返回 null+记录错误日志
        log.error("主备数据源爬取均失败,fullCode={}", fullCode);
        return null;
    }

四、核心优化点与生产环境适配

上述实现已满足基础需求,但在生产环境中需补充以下优化点:

  1. 缓存优化:对股票详情数据添加 Redis 缓存,key 为 STOCK_DETAIL + fullCode,过期时间设为 5 分钟,减少重复爬取。
  2. 反爬机制适配:维护 User-Agent 池,每次请求随机选择,降低反爬风险。
  3. 请求频率控制:通过线程池 + 计数器限制爬取频率,避免被封禁 IP。
  4. 数据源健康监控:记录主备数据源的爬取成功率,低于阈值时发送告警。
  5. 字段校验增强:对 DTO 封装后的字段进行非空校验,若为空则填充默认值,避免空指针异常。
  6. 降级策略:当主备数据源均失败时,返回最近一次缓存的股票详情数据,提升用户体验。

五、总结

本文完成了量化系统数据展示层的核心模块——股票详细信息实时获取,实现了多数据源爬取、自动切换、数据封装的完整逻辑。后续将结合实时详情数据与自选股票功能,构建自己的股票实时查看系统。在高并发场景下,如何设计缓存策略兼顾性能与数据实时性,值得进一步探讨。

目录

  1. 一、核心需求与数据模型设计
  2. 1.1 核心需求边界
  3. 1.2 核心数据模型:StockShowInfoDto
  4. 二、核心设计:多数据源架构与流程
  5. 三、核心实现:多数据源爬取与封装
  6. 3.1 主数据源:财联社股票详情爬取实现
  7. 3.2 备用数据源:腾讯股票详情爬取实现
  8. 3.3 数据源切换策略实现
  9. 四、核心优化点与生产环境适配
  10. 五、总结
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • GitHub Copilot 学生认证流程与 Python 自动化实现
  • 2026 年 3 月大模型全景解析:国产登顶与 Agent 工业化落地
  • 使用 KSWEB 在安卓部署 Typecho 博客并实现外网访问
  • GitHub 个人访问令牌 PAT 生成及 R 环境凭证管理与包安装配置
  • ComfyUI v0.18.0 发布:显存内存优化、VAE 架构进化与 API 前端升级
  • OpenClaw 开源 AI 智能体项目精选与部署指南
  • Qwen3-VL 法律场景长文档 OCR 结构化解析教程
  • SystemVerilog 教程:从基础到高级验证
  • PDF Arranger终极指南:快速掌握PDF页面重排的完整教程
  • 本地部署 Stable Diffusion 3.5 完整教程
  • VS2022 中 EPPlus 库安装、许可设置及使用指南
  • 即梦 AI 基础操作指南:绘画与视频生成入门
  • Qwen3-ASR-1.7B 实战案例:新闻发布会实时语音转写与关键人物发言提取
  • ClawPanel:OpenClaw 智能管理面板及 Docker 部署指南
  • 基于 Neo4j 知识图谱的智能问答系统设计
  • C++ 实现 UTF-8 与 GBK 字符编码转换及源码示例
  • Linux 基础文件与目录操作命令详解
  • 百考通 AIGC 检测工具功能解析与使用体验
  • 大模型、超大模型与 Foundation Model 技术精要
  • LoRA 技术详解:原理、训练理论与面经问答总结

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online