同一根K线,不同数据源可能给出不同结果。
你选的不是数据源,是翻译方式。
一个让我亏过钱的问题。
回测里某个信号持续有效,实盘对不上。差异不大但一直在。排查了三周,策略逻辑、滑点、手续费、执行延迟全查过。
最后发现问题出在K线时间标签的约定上——数据源把分钟标签落在“结束”,而团队的策略逻辑假设标签是“开始”。这个处理,数据商的文档里没有写,采购合同里也没有约定。
问题不在策略,在团队从没验证过数据源对市场做过的那些处理。
这篇文章要回答三个问题:
- 行情数据源的“翻译方式”到底有哪些差异?
- 这些差异怎么影响你的回测和实盘?
- 你怎么验证自己的数据源用的是什么翻译方式?
这篇文章写给三类人:
| 读者类型 | 你的核心任务 | 这篇文章帮你解决什么 |
|---|---|---|
| 量化投资者 | 跑全市场选股、做因子、做回测 | 为什么回测和实盘对不上,怎么排查数据层的定义问题 |
| 行情应用开发者 | 做看盘、做数据产品、做交易系统 | 怎么判断数据源的“全量”是否真的全,怎么验证 |
| 数据选型决策者 | 为团队选数据源 | 不同数据源的“翻译方式”差在哪,怎么对比 |
核心命题:你选的不是数据源,是翻译方式
从市场发生一笔成交,到你的屏幕出现一个数字,中间至少经过六次翻译。
市场事实 ──→ 时间戳 ──→ 分桶 ──→ 聚合 ──→ 复权 ──→ 截取 ──→ 修订 ──→ 你的屏幕
│ │ │ │ │ │ │
│ 第一次翻译 第二次翻译 第三次翻译 第四次翻译 第五次翻译 第六次翻译
│ │ │ │ │ │ │
│ 谁的秒? 从哪秒起? 纳入哪些? 谁算的? 给几档? 变过吗?
| 次序 | 翻译环节 | 核心问题 | 可能存在的做法差异 |
|---|---|---|---|
| 第一次 | 时间戳 | 这一秒,是谁的秒? | 起点/终点/接收时间 |
| 第二次 | 分桶 | 这一分钟,从哪一秒开始算? | 左闭右开/左开右闭 |
| 第三次 | 聚合 | 这一根K线,纳入了哪些成交? | trade condition过滤标准 |
| 第四次 | 复权 | 这个历史价格,是谁算的? | 前复权/后复权/除数驱动 |
| 第五次 | 截取 | 这个盘口,给了几档? | MBO/MBP/快照/增量 |
| 第六次 | 修订 | 这个历史数据,变过吗? | 修订窗口/是否可追溯 |
这六次翻译加在一起,就是你和市场之间的全部距离。
关键认知:不同数据源对这六次翻译的做法可能不同。你选数据源,不是选“谁的数据好”,是选“谁的翻译方式适合你的使用场景”。而这些翻译方式,大多数没有被写进文档,没有被写进合同。
第一次翻译:这一秒,是谁的秒?
这次翻译是什么
一条行情数据的时间戳,可能是六种时间之一。
事件时间 ──→ 源端时间 ──→ 发布时间 ──→ 服务端时间 ──→ 接收时间 ──→ 存储时间
│ │ │ │ │ │
市场真实发生 交易所打戳 数据源发出 数据商处理 你的系统收到 写入数据库
时间标签约定的差异
不同交易所和数据商的规格各异,使用前应核对时标定义。
Alpaca的官方文档说得很清楚:分钟K线在整分钟后发出,包含前一分钟的交易;迟到成交存在时,会在半分钟后发 updatedBars,示例中原K线的 t=16:49:00。这支持“起始标签”和“约30秒后的有条件更新”,但官方文档没有承诺“1秒计算、30秒必然重算”。
关于其他平台的时间标签,我看到过一些技术社区的讨论:
| 平台 | 技术社区讨论中的说法 | 来源 |
|---|---|---|
| Alpaca | 起始标签、整分钟后发出、迟到成交半分钟后发 updatedBars | Alpaca官方文档(2026-10-03查阅) |
| 米筐 | 社区讨论中提到结束标记 | 技术社区 |
| vnpy | 社区讨论中提到起始时间标记 | 技术社区 |
| 文华财经 | 社区讨论中提到时间段开始点 | 技术社区 |
| 金字塔 | 社区讨论中提到时间段结束点 | 技术社区 |
注意:上表中除Alpaca外的平台约定,来源是技术社区的第三方描述,我没有逐一实测或获取官方文档确认。采购或对接时,请以官方文档和实际样本验证为准。
你应该重点关注的
| 价值类型 | 内容 |
|---|---|
| 投资价值 | 时间标签错误导致信号在错误时间点触发。高频策略里,一分钟的差距足以让整个信号失效 |
| 场景价值 | 跨数据源对账时,两个数据源的时间标签约定不同,回测里信号在10:00触发,实盘监控里同一信号在09:59触发 |
| 风险价值 | 2010年5月6日美股闪崩后,监管机构事后重建市场时,发现数据碎片化和时间戳不一致导致难以拼凑完整图景。SEC在2016年CAT计划文件中称,当日重建仅含估计90%的交易与订单活动 |
收束:时间标签不是技术细节,是分析的基础假设。你不知道数据源怎么打标签,你的回测就是在别人的假设上跑。
第二次翻译:这一分钟,从哪一秒开始算?
这次翻译是什么
即使两家数据商都用“起始标签”,分桶规则也可能不同。
左闭右开: [9:30:00, 9:31:00) → 包含9:30:00,不包含9:31:00
左开右闭: (9:30:00, 9:31:00] → 不包含9:30:00,包含9:31:00
一次样本观测:A股K线的时间标签
A股取贵州茅台(600519.SH)2026年9月30日14:10–14:50(北京时间)。窗口内有763条逐笔记录,原始数量字段合计7,149。
在这组样本下,把K线时间直接当分钟起点,40个窗口均未对上;把它解释为分钟结束标签后,40个窗口成交量全部对齐。
这是一次数据实验的结果,不是供应商的接口约定文档。时间标签约定属于接口层的行为,样本对齐是验证起点,不能替代供应商的官方接口文档确认。 不同的标的、不同的交易日、不同的数据源,结论可能不同。建议在你自己的数据源上跑一遍相同的验证。
你应该重点关注的
| 价值类型 | 内容 |
|---|---|
| 投资价值 | 分桶规则不同,即使原始逐笔数据完全一样,聚合出来的K线也可能不同 |
| 场景价值 | 把A平台的数据导入B平台的框架,可能出现一根K线的偏移。你以为在比较两个数据源的质量,实际上在比较两套分桶规则 |
| 风险价值 | 跨数据源对账时,40个窗口全部对不上,排查三周才发现是标签约定问题 |
收束:分桶规则是数据商替你做的选择,不是市场的自然属性。
第三次翻译:这一根K线,纳入了哪些成交?
这次翻译是什么
不是所有成交都进入K线。
原始逐笔成交 ──→ trade condition过滤 ──→ 分桶 ──→ 应用sum/min/max ──→ K线
│
├── 过滤"typical" trades → Close price
├── 过滤大部分trades → Volume
└── 其他过滤标准 → Open/High/Low
聚合规则的差异
| 数据源 | 聚合规则 | 来源 |
|---|---|---|
| Alpaca | 三步骤:按执行时间分桶 → 按trade condition过滤 → 应用sum/min/max | 官方文档 |
| Alpaca引用标准 | CTS Specification p.64、UTP Specification p.43 | 官方文档 |
| 其他数据商 | 未公开聚合方法论 | 公开资料未找到 |
实测案例:港股取腾讯控股(700.HK)2026年10月2日15:00–15:05(香港时间)。最近逐笔样本覆盖了窗口前后,窗口内共221条记录,数量合计201,700;五个已结束分钟的数量合计分别与对应1分钟K线成交量相同,5个窗口全部对齐。
美股取苹果(AAPL.US)2026年10月1日15:30–15:45(纽约夏令时,UTC−4)。这段常规交易时段有15根历史1分钟K线和3根5分钟K线。按每五分钟聚合,3组开高低收及成交量全部相同,重复请求这段1分钟K线也得到相同结果。
但要注意:当前最近逐笔查询返回的是夜盘记录,没有取得该常规时段的历史逐笔,因此美股这里验证的是K线聚合一致性,逐笔完整性仍待验证。
另一个需要留意的点:在固定时窗查询中,AAPL.US 日线的 volume 含小数、quote_volume="0";但同日 limit=100 查询返回的是整数成交量和非零成交额,部分 OHLC 精度也不同。这是两条查询路径之间的数据差异,尚不能认定哪一个是准确口径。正文数值和计算示例暂勿混用两条路径。
你应该重点关注的
| 价值类型 | 内容 |
|---|---|
| 投资价值 | 你看到的成交量,是数据商过滤后的结果,不是市场的全部成交 |
| 场景价值 | 用成交量做资金流分析,如果数据商过滤标准不同,你的分析结果可能完全不同 |
| 风险价值 | 同一根K线的收盘价和成交量可能不同,但你在比较两个数据源时,以为在比较“市场” |
收束:K线不是逐笔的简单聚合,是数据商按自己的标准筛选后的结果。
第四次翻译:这个历史价格,是谁算的?
这次翻译是什么
复权不是市场的事实,是数据商的计算。
交易所发布除权参考价 ──→ 数据商回溯计算 ──→ 前复权/后复权价格
│ │
│ ┌─────┴─────┐
│ │ │
│ 前复权 后复权
│ (以现价为基准) (以上市首日为基准)
│ │ │
│ 历史价格变动 历史价格钉死
│ (未来函数) (推荐回测)
复权处理方式的差异
| 市场/数据源 | 复权处理方式 | 来源 |
|---|---|---|
| A股交易所 | 发布“除权参考价”(除权日当天的基准价);前复权和后复权是数据服务商基于参考价回溯或推演计算的结果 | 上交所数据文件接口规格、深交所权益分派公告 |
| NASDAQ | Nasdaq Last Sale(NLS)数据馈送中有 Adjusted Closing Price 消息 | Nasdaq Last Sale 规格 |
| Refinitiv | 指数层面采用除数驱动法,在除息日次日调整指数除数 | LSEG Refinitiv指数方法论 |
关键认知:不是所有交易所都不提供调整后价格。同一个词“复权”,在两个市场的处理路径可能完全不同。
说明:关于“所有复权序列都由数据商计算”,目前找到的是上交所和深交所对除权参考价的官方说明,后半句是根据数据产品流程的推断,不是交易所原话。
这跟你有什么关系
| 价值类型 | 内容 |
|---|---|
| 投资价值 | 前复权在日频回测中是一个未来函数。你今天用前复权价格回测,明天某只股票除权了,历史价格变了,你昨天的回测结果就不可复现了 |
| 场景价值 | 做跨市场对比时,A股的前复权是数据商算的,NASDAQ的Adjusted Closing Price是NLS数据馈送里的消息 |
| 风险价值 | 公司行为处理顺序不同(先分红后拆股 vs 先拆股后分红)会产生不同因子。你从不同数据商买的“复权后价格”,本质上可能是不同的东西 |
收束:复权不是一个“有没有做对”的问题,是“看你的使用场景”。信号生成用不复权或后复权,收益计算用后复权,展示给用户看用前复权。三者混用,就是未来函数。
第五次翻译:这个盘口,给了几档?
这次翻译是什么
“有盘口”这三个字,可以指十几种不同的东西。
盘口规格的差异
| 市场 | 盘口规格 | 关键差异 |
|---|---|---|
| 上交所 Level 2 | 十档、逐笔成交、首档前50笔订单委托量 | 产品页未见完整逐笔委托流承诺 |
| 深交所 Level 2 | 五档扩十档、逐笔委托与逐笔成交、最佳价位前50个分档明细 | 有逐笔委托 |
| HKEX BMP | 以 HKEX BMP 许可指引为准 | 延时数据至少15分钟,具体混合条件需查许可正文 |
| NASDAQ | OUCH(下单/自身订单回报)与ITCH(订单簿市场数据) | 订单输入和市场数据分离 |
| LSE GTP | 支持MBO(Market by Order)和MBP(Market by Price)两种模式 | MBO逐笔订单 vs MBP价格档 |
| 期货市场 | 快照,250ms或500ms推送 | 大部分交易所250ms或500ms |
说明:上交所的“首档前50笔订单委托量”来自上证所信息网络官方产品页,该页没有承诺完整逐笔委托流,但不能简单写“无委托数据”。深交所的逐笔委托与逐笔成交来自深圳证券信息有限公司增强行情说明。
你应该重点关注的
| 价值类型 | 内容 |
|---|---|
| 投资价值 | Level 1快照掩盖两次更新间的快速变化;增量更新若存在节流或丢包可能遗漏关键变动 |
| 场景价值 | 你的产品给用户展示“实时盘口”,用户看到的是HKEX的BMP数据,但BMP的延时条件需按许可指引确认。用户以为他在看实时数据,实际上可能在看延时数据 |
| 风险价值 | 用延时盘口估算实盘滑点,等于在错误的流动性假设下建立仓位管理规则。这不是技术问题,是产品合规问题 |
收束:采购时写“支持盘口”而不写规格,等于什么都没说。
第六次翻译:这个历史数据,变过吗?
这次翻译是什么
历史数据不是不变的。
历史数据修订 ──→ 修订窗口 ──→ 是否可追溯 ──→ 重复查询是否一致
│ │ │ │
│ 1秒/30秒/更长 有版本记录? 两次查询diff?
│ │ │ │
└── 不能复现的数据,在争议时无法自证
修订机制的差异
| 数据源/监管 | 修订机制 | 来源 |
|---|---|---|
| Alpaca | 整分钟后发出,迟到成交存在时半分钟后发 updatedBars | Alpaca官方文档 |
| MiFID II | 对算法交易监测系统有要求 | ESMA市场结构问答 |
| 中国证监会 | 核心机构和经营机构的重要信息系统,业务日志保存5年以上,系统日志6个月以上 | 2023年《证券期货业网络和信息安全管理办法》第十八条 |
| 其他数据商 | 未公开修订机制 | 公开资料未找到 |
说明:关于 MiFID II,ESMA 市场结构问答中对 Article 13(1) 的描述是算法交易监测系统;本轮未证实其为“回放要求”。文章中不再精确引“RTS 6 第13条要求回放”。
实测样本:同一 AAPL.US 1m 历史窗口连续两次返回的 data 完全相同,共 11 根。这说明本次重复调用一致,但不能推出历史数据永不修订。
另一个需要留意的点:逐笔 ID 跨查询稳定性需要单独确认。limit=10 与 limit=30 的相同 ID 分别对应不同的价格和方向。同 ID 不代表同笔交易,不能直接作跨查询去重键。
你应该重点关注的
| 价值类型 | 内容 |
|---|---|
| 投资价值 | 没有可靠事件标识,重连后重复计数,资金流被高估 |
| 场景价值 | 你昨天跑的回测,今天用同样的参数跑,可能得不到同样的结果——不是你的代码变了,是数据源修订了历史数据 |
| 风险价值 | 不能复现的数据,在争议时无法自证 |
收束:可复现性不是技术洁癖,是监管已经在做的事。
六次翻译加在一起,就是你和市场的距离
这六次翻译加在一起,就是你手里那张行情数据。你从来没问过数据商这六次翻译是怎么做的,但你的团队每天都在用翻译的结果做决策。
这不是说数据商做错了。是说,同一份市场,可以有不同的翻译方式,而你没有确认过你用的是哪一种。
采购/验收行情数据源时,我会先问这六个问题
| 验收维度 | 写进合同的问题 | 对应第几次翻译 | 不确认的后果 |
|---|---|---|---|
| 时间标签 | 分钟K线的时间标签是起点还是终点?分桶规则是左闭右开还是左开右闭? | 第一次、第二次 | 跨源对账出偏差,排查三周才发现 |
| 聚合规则 | K线纳入哪些trade condition?成交量是否过滤? | 第三次 | 资金流分析结果与数据商过滤标准绑定 |
| 复权处理 | 复权是你们算的还是交易所提供的?复权因子公式是什么? | 第四次 | 跨市场对比失效,前复权产生未来函数 |
| 盘口规格 | “支持盘口”具体指几档?快照还是增量?更新频率多少?有没有延时? | 第五次 | 产品展示延时数据,用户以为是实时 |
| 事件标识 | 逐笔成交有没有唯一标识?跨查询是否稳定?重连后如何去重? | 第六次 | 重连后重复计数,资金流被高估 |
| 历史修订 | 历史数据会不会修订?修订后能否追溯?重复查询结果是否一致? | 第六次 | 回测不可复现,争议时无法自证 |
这张表的读法是:每一行都是一个采购合同里应该写清楚的条款。不是“数据质量好不好”这种模糊表述,是“时间标签是起点还是终点”这种可以写进合同、可以验收的具体条件。
每个需求留六项:业务用途、样本区间、判定方法、通过条件、未通过时的处理、证据文件。验收样本至少覆盖正常交易、开收盘、无成交或停牌、断线重连与历史翻页。
这些验收维度不是我个人发明的。MiFID II、CFTC、中国证监会的要求说明,数据可复现性和唯一标识是行业已经在做的事。
这些验收维度,我在试接时用TickDB跑了一遍。
一段可运行的验证代码
上面六次翻译的差异,你可以用下面这段代码验证你的数据源。这段代码用 TickDB 的接口跑了一遍,你也可以直接复制运行。
import requests
API_KEY = "your_api_key"
BASE_URL = "//api.tickdb.ai/v1"
headers = {"X-API-Key": API_KEY}
# 验证时间标签
resp = requests.get(
f"{BASE_URL}/market/kline",
params={
"symbol": "AAPL.US",
"type": "stock",
"interval": "1m",
"limit": 1,
"start_time": 1790883000000,
"end_time": 1790883060000,
},
headers=headers
)
kline = resp.json()["data"]["klines"][0]
print(f"K线时间标签: {kline['time']}")
print(f"请求窗口: 1790883000000 - 1790883060000")
if kline['time'] == 1790883000000:
print("标签落在: 起点")
elif kline['time'] == 1790883060000:
print("标签落在: 终点")
else:
print("标签落在: 其他位置")
# 验证复权因子
resp = requests.get(
f"{BASE_URL}/market/kline/ex-factors",
params={"symbol": "600519.SH", "type": "stock"},
headers=headers
)
factors = resp.json()["data"]["data"]["600519.SH"]
print(f"\n复权因子条数: {len(factors)}")
print(f"首条因子: {factors[0]}")
# 验证历史可复现
params = {
"symbol": "AAPL.US",
"type": "stock",
"interval": "1m",
"limit": 15,
"start_time": 1790883000000,
"end_time": 1790883899999,
}
resp1 = requests.get(f"{BASE_URL}/market/kline", params=params, headers=headers)
resp2 = requests.get(f"{BASE_URL}/market/kline", params=params, headers=headers)
print(f"\n两次查询结果一致: {resp1.json() == resp2.json()}")
说明:TickDB 的 REST 接口是按需快照,不是实时流;如果你需要逐 tick 的实时更新,应该改用 WebSocket 订阅。
bid_price、ask_price、spread这些字段来自 depth 接口,不在 ticker 接口里。
TickDB 是什么,在数据源选型中有什么优势
上面这些验证,我用 TickDB 的接口跑了一遍。
TickDB 为开发者和 AI 应用提供统一的全球行情数据接口,让团队通过一套接入获取多市场实时与历史数据,更快构建行情、分析和监控产品。
在数据源选型这个场景中,TickDB 有三个可验证的优势:
| 优势 | 具体表现 |
|---|---|
| 多市场统一 | 一套 API 覆盖 A股/港股/美股/期货/外汇,标的目录可查询、可分类 |
| 字段结构确定 | 停牌、集合竞价等边界状态有明确字段行为,不是“看起来有数据” |
| 复权逻辑透明 | 复权因子有独立接口,公式可验证,不依赖数据源黑箱 |
如果你用的是支持 MCP 的工具(比如 Cursor、Claude Code),也可以直接让 Agent 调用 TickDB 的行情工具:
# 在支持 MCP 的 AI 工具中,配置 TickDB 的 MCP 服务后
# 可以直接用自然语言调用行情工具,例如:
# "帮我拉取 AAPL.US 最近 15 根 1 分钟 K 线"
# Agent 会调用 get_kline 工具,返回带时间戳、OHLCV 的结构化数据
# "查一下 700.HK 当前的盘口深度"
# Agent 会调用 get_order_book 工具,返回买卖档位
# "600519.SH 最近 5 个交易日的资金流向"
# Agent 会调用 get_capital_flow 工具,返回资金流数据
MCP 工具的价值在于:让模型先拿到带标的、字段和时间的事实,再进行分析——而不是让模型用训练数据里的历史价格回答“现在多少钱”。
数据源翻译约定确认表
把这张表填完,你对数据源的理解就到位了。
| 翻译层 | 要确认什么 | 供应商回答 | 是否写进合同 |
|---|---|---|---|
| 时间戳 | 标签是起点还是终点 | ||
| 分桶 | 左闭右开还是左开右闭 | ||
| 聚合 | 哪些 trade condition 纳入 | ||
| 复权 | 复权因子公式 | ||
| 盘口 | 几档、快照/增量 | ||
| 修订 | 修订窗口、是否可追溯 |
常见问题(FAQ)
Q1:行情数据源怎么选?
A:核心是确认六次翻译的约定:时间戳、分桶、聚合、复权、盘口、修订。这六个不确认,你在跨源对账、跨市场对比、产品展示时都可能出问题。
Q2:K线时间标签是起点还是终点?
A:Alpaca 官方文档说它用起始标签、整分钟后发出、迟到成交半分钟后发 updatedBars。其他平台有社区讨论提到不同做法,但未经官方文档确认。不同交易所和数据商规格各异,采购时要明确约定,并用实际样本验证。
Q3:行情数据需要复权吗?
A:取决于使用场景。前复权适合展示,后复权适合回测,但不同数据商的复权算法可能不同。A股的复权是数据商基于交易所除权参考价计算的,NASDAQ 的 Adjusted Closing Price 是 NLS 数据馈送里的消息。
Q4:“支持盘口”是什么意思?
A:可以指十几种不同的东西。要问清:几档?快照还是增量?更新频率?有没有延时?MBO 还是 MBP?
Q5:行情数据的历史数据会不会变?
A:Alpaca 的 K 线在整分钟后发出,迟到成交存在时半分钟后发 updatedBars。其他数据商的修订机制可能不同。要确认修订后是否可追溯。
Q6:行情数据源的采购合同该写什么?
A:至少写清:时间标签语义、分桶规则、聚合过滤标准、复权口径、盘口规格、事件标识机制、历史修订策略、数据保留期限。
结尾
你的数据源,敢不敢让你问一句“这个数字是怎么变成现在这样的”?
不用写代码。先做一件最小的事:在采购合同或产品文档里,加一条“数据源翻译约定确认”。确认三件事——时间标签怎么打、复权谁算的、历史数据会不会变。
我现在会把“连通成功”当成试接的开始。能否说明每段数据如何识别、如何对账,出了差异怎样复现,才是报价源进入下一阶段的验收答案。
参考文献
- Alpaca. Real-time Stock Pricing Data. 访问日期:2026-10-03.
- Nasdaq Trader. Nasdaq Last Sale Specification 3.0. 访问日期:2026-10-03.
- 上海证券交易所. 市场数据文件接口规格. 访问日期:2026-10-03.
- 深圳证券交易所. 权益分派公告例. 访问日期:2026-10-03.
- 上证所信息网络有限公司. Level-2 行情产品页. 访问日期:2026-10-03.
- 深圳证券信息有限公司. 增强行情说明. 访问日期:2026-10-03.
- HKEX. Basic Market Prices (BMP) Service Guiding Notes. 访问日期:2026-10-03.
- Nasdaq Trader. OUCH 产品页及 TotalView-ITCH 5.0 规格. 访问日期:2026-10-03.
- SEC. CAT Plan Filing (34-77724). 访问日期:2026-10-03.
- CFTC. Parts 43/45 Technical Specification. 访问日期:2026-10-03.
- ESMA. Market Structures Q&A. 访问日期:2026-10-03.
- 中国司法部. 《证券期货业网络和信息安全管理办法》. 访问日期:2026-10-03.
- LSEG. Refinitiv Global Equity Indices Methodology. 访问日期:2026-10-03.
- TickDB. REST API 官方文档及实测数据. 访问日期:2026-10-03.

