A股实时数据API:请求成功,不等于名单里每只票都有数据
TickDB Research ·
摘要:本文写给负责自选股看板的产品经理,以及参与投研数据源选型的负责人。接入A股实时数据API之后,怎么确认名单里每只股票这一轮都拿到了数据?怎么避免把没返回的行、或者旧价格,当成正常更新?文章用TickDB批量行情快照的真实结果,加上国内外机构资料和反例,把名单核对、数据时间和交易窗口拆开讲,并提供页面检查清单、Python脚本和五项边界自测材料,可以直接转给技术同事验证。
本文回答三个问题:
- 批次成功,为什么名单可能不全?(第一章)
- 一条记录拿到了,怎样判断它是否可用?(第二章)
- 少一行数据,会影响哪些后续工作?(第六章)
10月19日15:52,收盘后我做了一次受控测试:输入三个代码——两只正常股票,加一个受控的无效代码。请求返回成功,两只正常股票都有记录,第三个代码没有出现。
请求成功了,名单里却有一行没有行情。 如果页面只显示一个"更新成功",使用者根本不知道:这一轮到底谁拿到了数据,谁还需要处理。
解决办法不复杂:从原始名单逐只核对,再结合每条记录的时间和交易窗口,给每一行一个说明。TickDB为行情应用提供市场数据,本例用的是它的REST批量行情快照,一次按需查询;交易日历和交易时段也参与检查。最终,名单里的每一行都要有交代。
一、同一批请求成功,可以有代码没有返回
本节结论:批次成功与名单齐全,要分别检查。
这次输入的是 600519.SH、000001.SZ、999999.SH。接口返回 HTTP 200、业务码 code=0,结果列表里只有前两只;受控代码 999999.SH 缺席。

图1:按2026年10月19日15:52的独立受控测试绘制。右下虚线框是核对后的应用提示,不是接口返回的一条记录;该控制输入不计入正常股票样本。
这个结果直接说明了一件事:批次成功与名单齐全,要分别检查。
HTTP标准里,200只表示请求到了服务器、被受理了。返回内容到底对不对,要按具体请求去看。它不会替你核对"输入的代码是不是都在结果里"。RFC 9110,第15.3.1节
同组还独立查了两个受控代码,并测了 symbols 参数为空和缺失的情况。前两项成功返回空列表;空参数、缺参数两项返回 HTTP 400、业务码 2001。五项原始响应都保留在附件里。
这些结果只对本次输入、这个账户、收盘后这个时段有效。它们没有验证退市、代码变更或权限不足时会发生什么,也不能推出"只有参数错误才会整批失败"。收盘后测试,看的是返回结构;盘中数据是不是按要求更新,要另外查。
如果你是产品经理,这句话可以直接写进需求:原名单里的每一行,这一轮要么有结果,要么有待处理说明。只遍历返回列表,你看到的是"谁回来了";只有对照原名单,才能发现"谁还没回来"。
如果选择暂留上次价格,记得把上次的数据时间和"本轮未收到"一起带上。缺席的行不能悄悄删掉,也不能填成0,更不能直接标成停牌。
批次层与行级层,是两个检查对象
批次层: HTTP 200 / code=0 ──► 批次受理成功
│
▼
行级层: 返回列表 [600519.SH ✓, 000001.SZ ✓]
│
▼
应用层逐行对照原名单
│
┌───────┼───────┐
▼ ▼ ▼
received received missing
(999999.SH)
图2:批次层与行级层的逻辑分离示意。批次受理成功,不等于行级逐条返回;missing 只有在应用层逐行对照时才会出现。
二、两个时间一起看,价格才有上下文
本节结论:产品团队需要同时知道——数据源标注了什么时间,你的系统什么时候收到它。
回看同日上午的正常查询。北京时间10:07:40.949,脚本收到三只股票的行情快照:
| 股票代码 | 返回价格 | 数据时间(北京) | 本次应用结果 |
|---|---|---|---|
600519.SH | 1343.99 | 10:07:36.000 | 已收到,符合示例时间要求 |
000001.SZ | 11.57 | 10:07:36.000 | 已收到,符合示例时间要求 |
300750.SZ | 272.38 | 10:07:36.000 | 已收到,符合示例时间要求 |
输入三行,报告也保留三行。行情、日历和时段查询都成功,日历包含当天,时段和沪深常规连续竞价窗口一致。这是上午的正常样本,和下午混入无效代码的控制测试分开看。
拿11.57这条记录来说,产品团队需要同时知道两件事:数据源标注的是什么时间,你的系统是什么时候收到它的。这条记录的数据时间是10:07:36.000,本机接收时间是10:07:40.949,两者差了大约4.9秒。
两个时间,一条时间轴
10:07:36.000 10:07:40.949
●━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━●
│◄────────── 约 4.9 秒 ──────────►│
│ │
数据时间 本机接收时间
(这条记录标注的时刻) (你拿到它的时刻)
├──── 距今 ≤ 120 秒 ────► received
└──── 距今 > 120 秒 ────► stale(应用层阈值)
图3:两个时间与120秒应用阈值的关系示意。120秒是可调整的应用演示参数,不是TickDB的时效承诺;4.9秒是源时间与本机接收时间的差值,不是端到端延迟测量。
脚本把连续竞价时段的数据时间要求设成120秒,所以三行都通过了这次检查。120秒是可以调的应用演示参数;4.9秒是源时间与本机接收时间的差值,不是从交易所到屏幕的端到端延迟测量。
向供应商确认时,还要问清一件事:这个时间戳到底是哪个环节的时间?成交发生、行情记录生成、服务更新、本机接收,可能是四个不同的时刻。TickDB文档说明 timestamp 为毫秒Unix时间戳,本篇按返回的数据时间使用,不自行解释为每笔成交的精确发生时间。快照字段说明
三只股票这次时间值相同,也只能说明这一次观察。它不能证明数据源始终同步,也不能证明所有记录都来自同一个严格一致的源快照。
三、价格没变,先别急着判成数据停更
本节结论:数字有没有跳动,不能单独说明数据连接是否正常。
价格一直没动,就一定是接口卡住了吗?
Nasdaq的投资者教育材料提醒:最近成交价来自最近一笔成交;成交少的证券,价格可能很久才变一次。所以,光看数字有没有跳动,判断不了数据连接是不是正常。Nasdaq:Why Real-Time Data Matters When Trading Stocks
这个反例会改变检查方法:价格、数据时间、当前交易状态要放在一起看,还要理解时间字段的含义。只看价格不够,只看一个时间戳也诊断不了故障。
如果记录超过团队设置的时间要求,页面可以显示"截至某时,待核对",再查原始响应、交易状态、权限和本机时钟。不要直接把它写成"股票停牌"或"供应商故障"。
这次还没有做连续快照推进和同批时间戳分布的盘中观察,也没有真实的过期报价案例。文章没有把"价格未变、时间未推进"包装成亲历故障——这些问题得靠新的盘中记录来回答。
四、午间保留上午价格,和盘中旧价要分别解释
本节结论:旧价格可以保留,时间与状态也应一起保留。
同一条上午的数据,放在12:10和连续竞价时段,页面该怎样说明?
沪深交易规则都把股票常规竞价分成开盘集合竞价、连续竞价和收盘集合竞价。连续竞价为9:30—11:30、13:00—14:57,收盘集合竞价为14:57—15:00。午间没有连续竞价,不宜照搬盘中的时间要求。上交所2026年修订规则,第2.4.2条 · 深交所2026年修订规则,第2.3.2条

图4:区段宽度不按时长比例。示例时间阈值适用于上午和下午两段连续竞价;集合竞价单独处理。
一个可行的页面方案是:午间保留最近数据和它的截至时间,提示"当前处于午间间隔";进入连续竞价后,再按团队约定检查。临时停市、个股停复牌、盘后固定价格交易,另做处理。
国外专业机构也提供了"旧记录可以有明确用途"的反例。IBKR的TWS API区分Live、Frozen、Delayed和Delayed Frozen;Frozen用于取得收盘时最后记录的数据。记录较旧,可能来自明确的数据类型和使用安排。IBKR:Delayed Market Data
这里借鉴的是"把数据类型和用途讲清楚"这个做法;IBKR的分类不等于TickDB返回的字段。对采购团队来说,更值得确认的是:账号拿到的是什么类型的数据、哪些时段提供什么记录、页面怎么告诉使用者。
旧价格可以保留,时间与状态也应一起保留。 午间有截至时间的上午价格,和盘中没有说明的旧价格,带给使用者的信息并不相同。
五、最近成交价已取得,仍要明确它用来做什么
本节结论:用最新成交价观察自选股列表和研究名单是一类任务;判断买卖能否成交、多少数量能成交,则需要进一步核对买卖报价、数量和交易规则。
通过了这次时间检查,能不能直接把这条价格用作下单依据?
TickDB把 last_price 定义为最新成交价。深交所规则把最近成交价与买卖申报价格、数量分别列入即时行情,它们表达的是不同的信息。快照字段定义 · 深交所规则,第5.2.2条
美国SEC的Investor.gov也提醒:最近成交价,不一定是市价单最终成交的价格。这里引用的是这个概念区别,不套用美国交易制度。Investor.gov:Types of Orders
用最新成交价观察自选股列表和研究名单,是一类任务;判断买卖能不能成交、多少数量能成交,要另外核对买卖报价、数量和交易规则。
所以,本例里的 received 只表示这一行通过了本次应用检查,不代表交易许可,也不保证成交价格。需求里要写清"这格价格用来做什么",别让下游把列表展示的结果直接拿去做交易判断。
六、少一行数据,会影响哪些后续工作?
本节结论:产品与选型讨论因此不能只问更新速度,还应分别检查完整性、时间含义和异常处理。
设想一个团队用自选股名单来驱动页面和价格提醒。如果某一行这一轮缺席,页面继续显示旧值、又没有任何提示,使用者就分不清:是价格没变,还是这一轮根本没拿到数据。
如果后面的提醒又直接用这个旧值,影响还会传到提醒判断上。这是产品设计里要处理的条件场景;本次测试没有测量客户损失、返工成本或实际策略影响。
一行 missing 的下游传导
某行本轮 missing
│
▼
页面继续显示旧值,无提示
│
▼
使用者无法判断:没变化 / 没拿到数据
│
▼
提醒/下游判断使用旧值
│
▼
判断失真,且难以回溯
图5:条件场景示意,非实测损失。本次测试没有测量客户损失、返工成本或实际策略影响。
所以,产品与选型讨论不能只问"更新速度",还要分别检查完整性、时间含义和异常处理。巴塞尔委员会的风险数据原则,也是把准确性、完整性和时效性分开提的,并说明时效要求取决于风险性质和用途。这套原则面向银行风险数据,本篇借的是"分维度检查"这个思路,不把它当成行情看板的监管要求。BIS/巴塞尔委员会,第36.18节
下面这张检查单可以直接交给产品与技术同事:
| 页面或报告里看到什么 | 还不能直接得出什么结论 | 交付时怎样处理 |
|---|---|---|
| 请求成功 | 原名单全部有数据 | 从原名单逐行核对返回代码 |
| 本轮没有某行记录 | 停牌、退市或权限不足 | 留行、说明待核原因,再查原始返回 |
| 价格没有变化 | 数据连接停更 | 核对数据时间、字段含义及交易状态 |
| 午间停在上午价格 | 必须清空或报故障 | 保留截至时间,说明午间间隔 |
| 最近成交价已取得 | 下一笔可按该价成交 | 按用途另查买卖报价与交易条件 |
验收单上再加三个问题:缺席的时候,保留什么、暂停什么?出了问题,能不能定位到原始响应、用同一份名单重跑?账号范围、调用额度、展示和再分发权限,确认了吗?一次成功查询,证明不了这些许可。
七、两份工具,分别检查正常名单和边界输入
文章附件有两份Python脚本,需要Python 3.9及以上版本,只用标准库;本机要有可用的受信任HTTPS证书库。密钥通过环境变量传入,放在服务端使用。
正常名单:生成逐行报告
export TICKDB_API_KEY='你的密钥'
python3 batch_watchlist.py \
--symbols 600519.SH,000001.SZ,300750.SZ \
--freshness-seconds 120 \
--output watchlist_run_01
快照文档规定单次最多50个代码。脚本先去重分批,最后按原名单回填,重复输入行仍保留。批量查询参数
输出包括逐行CSV、各批次和日历/时段的原始响应、运行汇总。CSV里保存代码、数据时间、接收时间、窗口、状态、原因和下一步;价格按代码到原始响应里核对。
received 表示这一行通过了本次连续竞价时间检查;missing 表示成功批次里没有所查的代码;stale 表示超过了应用阈值;请求、字段或交易窗口不足以判断时,记为 unknown。全部行都是 received,退出码为0;有待处理行,退出码为1;参数或密钥缺失,退出码为2。午间这类窗口也可能得到 FAIL,要看行级原因,别直接当成数据源故障。
边界输入:记录接口怎样响应
python3 boundary_probe.py boundary --output boundary_run_01
边界采集器先查CN目录,再发出五组受控输入,保存 boundary_cases.csv、原始响应和请求元数据。和正常名单脚本不同,它会真的向服务端发空参数和缺参数请求。复跑时,"目录未见代码"这一项要按当次目录重新选;结果怎么解释,要看目标接口自己的约定。
| 自测内容 | 本次观察 | 复跑时检查什么 |
|---|---|---|
| 指定受控代码 | 成功返回空列表 | 是否有记录,错误或空结果如何表达 |
| 本次目录未见代码 | 成功返回空列表 | 目录范围与返回结果能否对应 |
| 正常代码加受控代码 | 正常两只返回,控制代码缺席 | 逐行核对能否指出缺席代码 |
| 参数显式为空 | HTTP400/业务码2001 | 与文档约定是否一致 |
| 参数缺失 | HTTP400/业务码2001 | 与文档约定是否一致 |
这张表记录的是本次观察,不是说所有数据API都得用同一种错误策略。采集器的 PASS 只表示五项都拿到了HTTP响应,不能当成逐行行情检查通过。
每次跑都另建输出目录,保留旧记录。上午三只股票的正常结果、下午五项边界结果和完整代码都随文提供;连续时间戳分布、推进观察、真实过期报价,以及超过50只代码的盘中运行,尚未完成。正常名单脚本只接六位代码加 .SH 或 .SZ,不能拿它推断TickDB全部市场范围。
常见问题
1. 第一次接入A股实时数据API,先做什么?
先确定页面用途和需要的数据对象,再选两三只有查询权限的股票,跑一遍正常名单检查。产品经理可以先读样本CSV和检查单,把自己的名单和展示要求交给技术同事。
2. 缺失或超过时间要求,怎样定位和重跑?
先看行级原因,再查对应原始响应里的HTTP状态、业务码、代码和时间。复核权限、交易窗口和本机时钟之后,另建目录重跑。证书校验失败,就修信任配置,别关掉HTTPS校验。
3. TickDB后续怎样用于持续看板?
本例完成的是REST按需快照检查。持续更新,可以按需求设计重复查询,也可以另外验证WebSocket推送;两种方式都要安排异常复查和监控。本文没有验证持续推送、断线恢复或消息完整性。
请求成功之后,原名单里的每一行仍应有交代:有没有拿到数据、来自什么时间、现在怎样展示、异常下一步查什么。
今天就可以打开自己的自选股页面,挑一行问:如果下一轮没有拿到它的数据,使用者看得出来吗?把这份名单与检查单交给技术同事,对照页面和报告是否给出了相同答案。
本文用于行情研究和产品检查,不构成投资建议。实测及资料核验日期:2026年10月19日。
参考资料与实测附件
- IETF:RFC 9110,第15.3.1节,200 OK。2022年6月;区分请求成功与名单核对。
- Nasdaq:Why Real-Time Data Matters When Trading Stocks。2024年3月25日;解释最近成交价与成交频率的差异。
- 上交所:《交易规则(2026年修订)》及发布通知。2026年4月24日发布;常规竞价时段见第2.4.2条。
- 深交所:《交易规则(2026年修订)》。2026年4月24日修订;时段及即时行情内容见第2.3.2、5.2.2条。
- Interactive Brokers:Delayed Market Data。官方TWS API文档;提供有明确用途的冻结记录这一反例。
- 美国SEC Investor.gov:Types of Orders。官方投资者教育资料;说明最近成交价与执行价格的区别。
- 巴塞尔委员会:《Principles for effective risk data aggregation and risk reporting》。2013年1月9日发布;现行框架第36.18节核对准确、完整、时效原则及银行适用范围。
- TickDB:行情快照文档。核对字段、时间单位与批量查询上限。
- 本篇附件:正常名单脚本、边界采集脚本、运行说明,及上午正常样本、独立空结果控制和下午五项边界测试的原始响应。外部资料解释机制,实测记录支持具体返回结果。