美股夜盘数据怎么获取?行情 API 接入与质量检查
TickDB Research ·
美股夜盘数据怎么获取?行情 API 接入与质量检查
摘要: 接入美股行情 API 后,如何判断返回的价格和成交量属于夜盘?本文结合三个美股标的的快照查询观察,讲清夜盘字段读取、跨午夜时间归属、缺失与零成交的区别,并提供可复制的请求示例和使用合成样本的 Python 校验代码,帮助检查美股数据源的夜盘数据质量。
查询接口返回了价格、时间戳和成交量,就能直接把它们用作美股夜盘行情吗?
还不能。一条响应可能同时包含常规盘、盘前、盘后与夜盘行情,不同对象的时间和统计窗口并不相同;一只股票整晚没有新成交,也可能是正常的市场状态。真正需要回答的是:哪些标的应当有数据、这些记录属于哪一晚、没有更新究竟意味着什么。
这套方法适用于自选股扫描、夜盘看板与研究数据入库。本次未进行整晚持续采集,不给出市场整体覆盖率、丢包率或供应商质量排名。
一、先明确正在检查哪一种夜盘数据
夜盘行情需要同时说明标的、时段、粒度和来源。缺少这些条件,同一个价格差异可能有完全不同的解释。
| 维度 | 要验证的问题 | 需要的证据 |
|---|---|---|
| 标的范围 | 约定的夜盘标的是否都被纳入? | 带生效日期的夜盘覆盖清单、标的映射及排除原因 |
| 会话范围 | 是否覆盖约定的一整段夜盘? | 会话起止、日历例外、采集和恢复日志 |
| 数据粒度 | 得到的是最新快照,还是完整成交事件? | 频道定义、历史边界、分页或序列及补发规则 |
| 场所范围 | 覆盖哪个交易场所或哪些来源? | 明确的场所列表和聚合口径 |
标的上市地与夜盘成交场所要分开记录。覆盖某上市市场的股票,并不自动等于覆盖这些股票在全部夜盘场所的成交。FINRA 的扩展时段说明也提醒,不同系统中的价格可能彼此不同;因此跨源价格不一致应先检查来源范围和时间,而不是直接判错。来源:FINRA 扩展时段说明

图 1:夜盘数据的四项检查边界,示意图。
建议给每次分析保留一份采集说明:目标会话、时区、预期标的清单版本、来源范围、数据类型、采集起止、失败请求、恢复情况及最终统计时间。这样今天的结果才有办法与明天比较。
二、覆盖率的分母,不能来自“这次返回了什么”
先定义预期集合 U:在目标会话内,按已确认覆盖清单应该纳入评估的标的。 如果股票在会话中途加入、暂停或恢复,需要记录生效区间,不能用今天的最新名单倒推历史夜盘。
再定义实际返回的唯一标的集合 R,以及通过本次必需字段和会话检查的集合 V。可以分别报告:
- 返回覆盖率:U 与 R 的交集数量 ÷ U 的数量。
- 本次规则通过覆盖率:U 与 V 的交集数量 ÷ U 的数量。
- 待解释清单:未返回、夜盘对象缺失、非目标会话、字段异常,分别列出代码和原因。
U 为空或根本没有可靠清单时,覆盖率应显示“不可计算”,不能默认 100%。只统计“有夜盘对象的行数 ÷ 返回总行数”,得到的只是返回样本中的字段出现比例。
更不能把“有成交的标的比例”作为数据完整率。无成交、权限不足、接口不覆盖、采集失败,都可能表现为没有一条新记录,但它们需要完全不同的处理。
三、先锁定夜盘会话,再解释时间戳
以 Blue Ocean 公布的常见夜盘窗口为例,时段为美东时间 20:00 至次日 04:00;实际采集仍应使用目标场所当日的日历和临时通知,不能只凭星期推算。来源:Blue Ocean 时段说明
入库时至少分开保存三类时间:原始行情时间、客户端接收时间、业务使用的会话日期。原始时间统一存 UTC,展示和切分会话时使用 America/New_York,避免把全年美东时间写死成 UTC−5。
例如 2026 年 10 月 8 日 20:00 至 10 月 9 日 04:00 美东时间,换算为北京时间是 10 月 9 日 08:00 至 16:00。不能按北京时间零点把这段会话切开,也不能直接拿 UTC 日期充当交易日。
“会话日期”与“成交发生日”也不能混用。Blue Ocean 的说明区分了 FIX Tag 75 中的会话日期和按实际美东成交时间记录的 TRF 日期。适配时应保留来源字段,另外计算自己的会话标签,不要覆盖原始日期。来源:Blue Ocean 日期口径说明
还要问清时间戳究竟表示最新成交、报价更新、快照生成还是会话汇总截止。如果一批记录都停在 04:00,先核实是否为会话结束标签;不能仅凭相同时间戳判定所有股票都在这一刻成交,也不能直接把边界值判成越界。
四、读对夜盘字段,别把常规盘快照当夜盘
一条股票记录可能同时带有常规行情、盘前、盘后与夜盘对象。做夜盘分析时,价格、成交量、高低价和时间必须来自同一个对象、同一个统计窗口。
下面的请求示例查询三个标的,适合先验证响应结构。文档限制单次最多查询 50 个标的;更多标的需按接口限制分批处理。本次通过行情工具取得了这三个标的的响应;下面的 curl 命令按官方接口文档编写,未在本次单独执行。 接口字段依据
# 先在本地设置自己的 TICKDB_API_KEY,不要写入稿件或仓库。
: "${TICKDB_API_KEY:?请先设置环境变量}"
curl --fail-with-body --compressed --get \
--connect-timeout 10 --max-time 60 \
-H "X-API-Key: ${TICKDB_API_KEY}" \
--data-urlencode "symbols=AAPL.US,MSFT.US,NVDA.US" \
--data-urlencode "type=stock" \
"https://api.tickdb.ai/v1/market/ticker" \
-o us_snapshot.json
保存响应后,先检查 HTTP 结果、业务状态码及数组结构。HTTP 成功只说明请求完成,还要检查目标标的是否返回、代码是否重复,以及每条数据的时间和字段条件。一次快照无法还原两次采样之间发生的全部成交。
本次单次查询中,三个标的均带有夜盘对象,且对象内时间戳相同。这个观察支持“按夜盘对象读取并检查时间语义”,但不能据此推断三只股票同时成交,也不能外推其他标的的可用性。查询记录中的顶层时间与夜盘对象时间不同,说明校验价格时必须同时取对应对象内的时间。

图 2:两种接入方式下的夜盘字段读取,文档示意,非持续采集结果。
适配层要保留三种不同状态:字段不存在、字段值为空、字段明确为零。只有最后一种才允许按零参与计算,而且还需要确认该零值属于目标会话。get("volume", 0) 会把缺失信息伪装成无成交,不适合用在质量统计中。
五、用一段可执行代码验证判定逻辑
下面的代码检查已经转换为统一格式的夜盘快照。event_time 是适配层字段,不是要求供应商使用的原始字段名;本例明确约定它表示事件时间,采用左闭右开会话区间。若来源给的是会话结束标签,必须先建立对应规则,不能直接套用本例。
Python 3.9+ 可运行,需要环境具备 IANA 时区数据。五条输入全部为合成数据,用于验证缺失、零值、跨会话和价格约束,不是线上行情。
from datetime import datetime
from decimal import Decimal, InvalidOperation
from zoneinfo import ZoneInfo
ny = ZoneInfo("America/New_York")
start = datetime(2026, 10, 8, 20, tzinfo=ny)
end = datetime(2026, 10, 9, 4, tzinfo=ny)
def check(q):
required = ("event_time", "last", "low", "high", "volume")
if not isinstance(q, dict) or any(
q.get(k) is None for k in required
):
return "MISSING"
try:
t = datetime.fromisoformat(q["event_time"])
if t.tzinfo is None:
return "INVALID_TIME"
p, lo, hi, vol = [
Decimal(str(q[k]))
for k in ("last", "low", "high", "volume")
]
except (ValueError, TypeError, InvalidOperation):
return "INVALID_VALUE"
if not all(x.is_finite() for x in (p, lo, hi, vol)):
return "INVALID_VALUE"
if not start <= t.astimezone(ny) < end:
return "OUTSIDE_SESSION"
if vol < 0 or not 0 < lo <= p <= hi:
return "INCONSISTENT"
return "ZERO_REVIEW" if vol == 0 else "RULE_PASS"
base = dict(event_time="2026-10-09T02:00:00+00:00",
last="100", low="99", high="101", volume=10)
samples = [base, None, {**base, "volume": 0},
{**base, "event_time": "2026-10-08T02:00:00+00:00"},
{**base, "last": "102"}]
for q in samples:
print(check(q))
实跑输出依次为 RULE_PASS、MISSING、ZERO_REVIEW、OUTSIDE_SESSION、INCONSISTENT。
RULE_PASS 只表示通过这几条本地规则;ZERO_REVIEW 表示保留零值并进一步核对语义。代码没有验证逐笔是否齐全,也没有证明其他市场没有更优价格。高低价约束同样有前提:最新价、高低价必须采用一致的成交范围及修订口径。
六、整晚质量报告还要补哪些证据
无更新与断流分开判断。 长尾股票可能长期没有成交;交易记录不变时,要结合连接状态、心跳、订阅确认和其他活跃标的判断。链路正常也不能证明单只股票数据完整,只能缩小排查范围。
记录年龄与传输延迟分开计算。 接收时间减去最新成交时间,可能包含市场本身的无成交间隔。只有时间戳语义、时钟同步和采集位置明确,才适合比较延迟分位数;没有同步误差预算时,负值也应先检查时钟与字段含义。
成交事件与累计值分开处理。 每秒采样的累计成交量不能直接相加。跨会话清零、迟到成交、撤销和更正都可能改变累计值;要先确认规则,再进行差分或逐笔重算。缺少修订消息时,应把聚合结果标为暂定。
重复与乱序依据协议判定。 有稳定事件 ID 时,按其唯一性范围去重;有序列号时,按频道、分区和重置规则查缺口。不要用“时间+价格+数量相同”直接删除记录,两笔真实成交也可能相同。没有序列或完整对账源时,不报告无法证明的丢包率。
价格偏离先进入复核队列。 夜盘可能出现较低流动性、较宽价差和较大波动。大幅偏离常规盘收盘价可以触发检查,但不能单独作为错误判据;复核需要同场所、同时间、同价格类型,并检查公司行动与复权口径。来源:FINRA 扩展时段说明
最终报告应同时给出分子、分母、排除原因和未知项。先按活跃程度、股票与 ETF、来源场所分组,再看整体指标,避免少数活跃股票掩盖长尾问题。阈值由用途决定:看板的新鲜度要求、研究的修订等待期与逐笔重放的完整性要求,应分别设定。
能说明每条记录属于哪个会话、每个缺口为何出现、每项结论依赖什么证据,才算完成一次可复核的夜盘数据质量分析。返回很多记录只是起点。