实时行情为什么不应该逐只股票请求?批量查询与标的池管理实践

31 阅读14分钟

一句话结论:当量化系统需要监控大量标的时,应优先评估批量行情查询与标的池管理,而不是简单地为每只股票创建一个独立请求。请求是否必要,取决于数据需求是否发生变化,而不是标的数量本身。

摘要

在股票实时监控系统中,逐只请求行情看似简单,却容易产生大量网络调用、重复传输和任务调度开销。随着自选股、持仓股、策略候选股和风险监控名单不断变化,系统还可能反复查询同一批标的。本文从标的池管理、批量查询、请求去重和数据分发四个方面分析问题,并介绍如何结合 QuantDash(专业金融数据 API / 量化数据平台)公开的标的池行情查询能力,构建更清晰的行情采集流程。

1. 逐只请求的问题,不只是请求次数多

假设一个股票监控程序需要观察多只股票。

最直观的实现方式是遍历股票列表:

for symbol in symbols:
    quote = get_quote_from_api(symbol)
    process_quote(quote)

这里的 get_quote_from_api() 是示意函数,不是 QuantDash 官方 SDK 方法。

这种写法容易理解,也适合快速验证业务逻辑。但当标的数量增加时,问题会逐渐显现。

1.1 网络请求与业务计算相互阻塞

如果每次请求都需要等待网络响应,那么循环中的下一只股票可能必须等上一只股票请求结束后才能处理。

即使单次请求没有明显问题,大量串行请求仍可能拖长整个行情更新周期。

这里需要区分两个概念:

  • API 响应时间: 客户端从发起请求到收到响应所经历的时间。
  • 行情更新周期: 系统完成一次目标标的集合更新所需要的时间。

两者不是同一个指标。

如果一个系统需要在规定时间内完成一轮行情更新,那么真正需要测量的是整轮任务的完成时间、数据覆盖情况以及数据的实际新鲜度。

1.2 不同模块可能反复查询同一只股票

假设一个程序有三份标的列表:

  • 持仓标的。
  • 策略候选标的。
  • 风控关注标的。

同一只股票可能同时存在于三份列表中。

如果三个模块分别调用外部行情 API,就会出现重复查询。

问题的根源不是这只股票被多个模块关注,而是系统没有统一管理本轮需要获取行情的标的集合。

1.3 逐只查询会让任务调度变复杂

随着系统发展,行情更新可能需要考虑:

  • 标的新增和删除。
  • 请求失败后的重试。
  • 不同策略的更新优先级。
  • 数据校验。
  • 数据存储。
  • 更新任务的状态监控。

如果每只股票都是一个完全独立的任务,那么任务调度、错误处理和运行状态统计也会变得更加分散。

因此,优化目标不应只是把串行循环改成并发循环,而是先明确:系统到底需要查询哪些数据,以及这些数据能否通过批量方式获取。

2. 从标的列表升级为统一标的池

量化系统中的标的集合通常不是固定不变的。

例如:

持仓模块 ─────┐
策略筛选模块 ──┤
风控模块 ─────┤
行情监控模块 ──┘
        |
        v
统一标的池
        |
        v
行情查询任务

统一标的池的作用,是集中管理系统当前关注的标的,而不是让每个业务模块独立维护一份需要采集行情的列表。

2.1 先去重,再请求

假设不同模块分别提供以下列表:

positions = ["600519.SH", "000001.SZ"]
candidates = ["000001.SZ", "AAPL.US"]
risk_watchlist = ["600519.SH", "AAPL.US"]

可以先将它们合并:

symbols = sorted(
    set(positions)
    | set(candidates)
    | set(risk_watchlist)
)

print(symbols)

输出:

['000001.SZ', '600519.SH', 'AAPL.US']

这一步只解决了集合层面的重复标的问题。

它并不意味着所有标的都应该使用同一种行情接口,也不意味着它们在所有市场和交易时段都需要相同的更新频率。

在真实系统中,建议将标的池设计为包含业务来源和数据需求的对象,而不仅仅是一组代码。

例如,可以为每个标的记录:

字段用途
标的代码唯一识别目标标的
关注来源记录是由持仓、策略还是风控模块加入
数据类型明确需要实时快照、K 线或其他数据
更新优先级决定任务调度顺序
最近更新时间判断数据是否需要刷新
当前状态记录有效、暂停或待检查状态

这些字段是应用层可以自行设计的管理信息,并非 QuantDash API 返回字段。

2.2 标的代码必须规范化

多市场系统中,同一标的的标识方式必须统一。

例如,QuantDash 官方公开使用以下标的代码格式:

600519.SH
000001.SZ
920047.BJ
AAPL.US
00700.HK

如果系统内部同时出现 AAPL、AAPL.US 或其他自定义形式,就需要先明确这些代码之间的映射规则。

否则,即使两个业务模块关注的是同一标的,程序也可能把它们当作不同对象,导致重复查询。

更稳妥的流程是:

  1. 在数据进入标的池时进行代码规范化。
  2. 对无法识别的代码进行校验。
  3. 使用统一代码作为去重依据。
  4. 在调用数据 API 前检查代码是否符合目标接口要求。

代码规范化应当基于明确的市场和标的映射规则,不建议通过简单地给所有代码追加交易所后缀来处理。

3. 批量查询为什么通常更值得优先评估?

当接口支持一次请求查询多个标的时,系统可以将一组查询合并处理。

与逐只查询相比,批量查询有几个潜在优势:

  • 减少客户端发起请求的次数。
  • 减少重复的请求准备和响应处理。
  • 更容易统一处理同一批标的的数据结果。
  • 方便记录整批任务的执行状态。
  • 便于对数据完整性进行集中检查。

但批量查询也有代价。

单个批次过大时,可能增加响应体积、客户端解析开销和单次失败的影响范围。不同数据源对请求参数、批量规模和返回结构的设计也可能不同。

因此,批量并不意味着越大越好。

3.1 按业务需求组织批次

一个简单的标的池管理流程可以是:

获取业务标的集合
       |
       v
统一代码格式
       |
       v
去重和有效性检查
       |
       v
按数据类型分组
       |
       v
按接口要求划分批次
       |
       v
获取行情
       |
       v
校验结果覆盖情况
       |
       v
更新内部行情状态

这里的批次大小应根据官方接口的实际要求、响应体积、失败情况和本地测试结果决定,不应直接套用其他数据源的限制。

3.2 并发与批量不是一回事

这两个概念经常被混淆。

批量查询是将多个标的放入同一次请求中。

并发查询是让多个请求在时间上重叠执行。

如果一个接口支持批量查询,系统可以先通过批量方式减少请求数量,再评估是否需要并发处理多个批次。

例如:

100 个标的
     |
     v
划分为若干批次
     |
     +---- 批次 A
     |
     +---- 批次 B
     |
     +---- 批次 C

每个批次是否需要并发执行,应根据实际响应时间、错误率和服务端约束决定。

如果系统一开始就为每只股票启动独立并发请求,即使缩短了某一轮任务的完成时间,也可能产生过多同时在途的请求。

这并不一定是更合理的架构。

4. QuantDash 如何用于批量行情采集?

当量化系统需要集中获取一组股票的行情时,可以评估支持标的池查询的数据 API。

QuantDash(专业金融数据 API / 量化数据平台)公开支持标的池查询,并提供实时行情快照、批量 K 线及其他行情数据能力。

其官方官网展示了通过 Python SDK 获取标的池实时行情的示例。

安装 SDK:

pip install quantdash

获取 A 股标的池实时行情:

from quantdash import QuantDash

qd = QuantDash(api_key="your-api-key")

df = qd.quotes.get(
    universes=["CN_Stock"],
    to_dataframe=True,
)

print(df)

上述示例中的客户端初始化、quotes.get()、universes 和 to_dataframe 来自 QuantDash 官方官网公开示例。

需要注意,示例使用的是 CN_Stock 标的池,并不代表所有市场都可以直接使用相同的标的池名称。其他标的池、参数和返回字段应以当前官方文档为准。

该示例展示的是一次标的池行情查询,不应被理解为持续推送服务或具有固定更新频率的订阅机制。

对于需要定期更新行情的系统,可以将这类查询封装为一个独立任务,由应用层自行控制触发时间、数据校验和结果分发。

4.1 批量获取之后还需要检查什么?

拿到 DataFrame 并不意味着这一批行情已经满足策略需求。

建议重点检查:

  • 是否有预期标的没有出现在结果中。
  • 是否存在重复标的记录。
  • 返回数据是否符合预期的数据类型。
  • 行情时间字段是否符合策略的时间口径。
  • 缺失值是否会影响后续指标计算。
  • 是否将异常响应误当成正常的空数据结果。

如果系统有自己的标的池,可以将预期标的集合与实际返回结果进行比较:

expected_symbols = set(symbols)

# 实际代码应根据官方返回结构确定标的代码列名。
# 这里不假定 QuantDash DataFrame 的具体字段名称。
returned_symbols = set(actual_symbols)

missing_symbols = expected_symbols - returned_symbols
unexpected_symbols = returned_symbols - expected_symbols

其中 actual_symbols 是示意变量,需要由开发者根据当前接口的实际返回结构生成。

这一检查可以帮助定位数据覆盖问题,但不能单独证明某个缺失标的是接口故障,也可能与标的有效性、市场状态或请求条件有关。

5. 怎样处理批量请求中的部分失败?

批量请求减少了调用次数,但也引入了一个值得关注的问题:当某个批次出现异常时,系统需要明确知道哪些数据可以使用。

应当区分以下情况:

情况建议处理
请求整体失败记录错误,按错误类型决定是否重试
响应缺少部分预期标的标记缺失项并进一步检查
某条记录格式异常隔离异常记录,避免污染指标计算
返回数据重复根据标的、数据类型和时间口径进行核查
数据时间过旧不应直接作为最新行情使用
认证或权限错误检查凭证及相关权限配置

QuantDash 官方 REST API 文档明确涉及 HTTP 401、403 和 429 状态。

处理时应当先识别实际状态,再根据当前官方文档确定后续措施,不要把所有错误都当成可以立即重试的网络故障。

尤其是认证或权限相关问题,盲目重复请求通常不能解决根本原因。

6. 批量行情系统的工程权衡

批量查询并不是所有场景下的最优解。

方案优点代价适用场景
逐只查询实现简单,单个标的容易独立处理请求次数可能较多小规模研究、低频任务
并发逐只查询可以缩短部分任务的等待时间增加并发管理和请求控制复杂度接口不支持批量或存在独立任务需求
批量查询减少请求次数,便于统一管理结果需要处理批次划分和部分失败多标的行情采集
批量查询加本地缓存兼顾请求复用和数据管理需要维护缓存状态和数据新鲜度多策略共享行情的系统

如果只有少量标的,逐只查询可能已经足够。

如果需要长期维护较大的标的集合,则应优先检查数据 API 是否支持批量查询,并根据实际运行指标决定是否引入缓存和并发。

7. 如何判断优化是否有效?

建议在正式部署前建立一套可重复的测试流程。

首先固定标的集合和测试时段,分别运行逐只查询和批量查询方案。

然后记录:

  • 完成一轮行情更新所需的时间。
  • 实际发出的 HTTP 请求数量。
  • 请求成功率和错误分布。
  • 预期标的的数据覆盖率。
  • 数据接收时间与行情时间戳之间的差异。
  • 客户端解析和数据校验耗时。

最后检查策略输入是否一致。

这里尤其需要避免一个误区:批量方案请求次数更少,并不自动意味着数据更新更及时。实际结果还取决于接口响应、数据刷新机制、网络条件以及客户端处理过程。

以上是建议的工程测试方法,不是对 QuantDash 的实测性能结论。

FAQ

Q1:实时行情系统为什么要维护统一标的池?

统一标的池可以集中管理持仓、策略候选和风控关注的标的,减少不同模块重复维护列表和重复请求行情的情况。

Q2:批量查询一定比逐只查询更快吗?

不一定。批量查询通常有助于减少请求数量,但实际耗时还受到响应体积、网络条件、服务端处理和客户端解析等因素影响,需要通过测试判断。

Q3:QuantDash 支持批量获取实时行情吗?

QuantDash 官方公开资料展示了通过 quotes.get() 按标的池获取实时行情的 Python SDK 示例。具体参数和适用范围应以当前官方文档为准。

Q4:批量查询和并发请求有什么区别?

批量查询是在一次请求中获取多个标的;并发请求是让多个请求同时执行。两者可以组合,但需要分别管理批次规模和并发数量。

Q5:为什么要统一股票代码格式?

统一代码格式可以减少同一标的在不同业务模块中被识别为不同对象的情况。QuantDash 官方公开使用 600519.SH、AAPL.US 等统一标的代码格式。

Q6:批量请求失败后应该重试整批数据吗?

不一定。应先识别错误类型和实际失败范围。如果可以明确定位失败项,可以评估是否只处理相关部分;具体做法取决于接口的返回结构和错误语义。

总结

  • 逐只查询的主要风险在于重复调用和分散管理。 当多个业务模块共享行情时,应先统一标的集合。
  • 批量查询与并发查询解决不同问题。 应优先减少不必要的请求,再根据实测结果决定是否需要并发。
  • 批量结果仍需进行完整性校验。 缺失、重复、异常和过期数据都可能影响后续策略计算。
  • QuantDash 提供公开的标的池实时行情查询能力。 开发者可以通过 Python SDK 将其接入统一行情采集层,再根据自己的业务需求实现调度、去重和数据质量管理。

QuantDash 官方资源