一些数据源的实际使用情况

数据源
ETF
量化研究
数据工程
记录 WZETF 在中国、美国、香港和台湾市场使用行情与基金净值数据时,遇到的口径、限流、服务器访问和数据发布问题。
作者

WZ ETF

发布于

2026-08-18

刚开始做 WZETF 时,我以为数据源问题只是找到一个接口,把行情下载下来。真正上线以后才发现,能拿到数据敢把数据稳定地发布给用户,完全是两件事。

WZETF 同时覆盖中国、美国、香港和台湾市场。每个市场的交易时间、节假日、代码格式、行情口径和数据发布节奏都不一样。更麻烦的是,同一个接口在本地电脑上可以正常工作,部署到云服务器后却可能超时、限流或者直接断开连接。

这篇文章记录我实际使用这些数据源时遇到的问题,以及后来逐步形成的处理方法。它不是一份数据源推荐清单,而是一篇真实的使用复盘。

多市场金融数据通过服务器采集、处理并输出到研究网站的示意图

WZETF 多市场数据采集与研究展示示意图

拿到价格,不等于拿到了可以使用的数据

最初的流程很直接:从公开数据源取得 ETF 行情,计算动能分,生成排行榜,再把结果展示到网站和 App。

上线后很快遇到第一个问题:大家口中的“价格”,可能指完全不同的数据。

  • 盘中最新成交价;
  • 某一分钟的价格;
  • 当日收盘价;
  • 前一个交易日收盘价;
  • 复权后的历史日线;
  • 基金单位净值。

这些数字都可能是正确的,但不能随意互换。

例如,中国市场需要判断 ETF 溢价率:

\[ \text{溢价率}=\frac{\text{ETF 市场价格}-\text{单位净值}}{\text{单位净值}} \]

这里的市场价格和基金单位净值来自两套不同的数据体系。净值还有 nav_date(净值日期)和 ann_date(公布日期)的区别。如果把当时尚未公布的净值提前用于计算,就会产生“回看时正确、实盘时不可获得”的未来数据问题。

这让我认识到,数据系统首先需要定义的不是接口,而是数据口径

多市场最麻烦的不只是时差

四个市场意味着四套交易日历和四套数据发布节奏。

美国、香港和台湾市场会遇到交易日不同、夏令时变化、午间休市和节假日不同步等问题。服务器时区如果和市场时区混在一起,任务就可能提前执行、延后执行,甚至在休市日误判为更新失败。

后来,每个市场的任务都使用自己的市场时区,并把流程拆成几个明确阶段:

  1. 判断该市场今天是否交易;
  2. 在约定时间采集价格;
  3. 检查数据日期、数量和有效性;
  4. 计算排行榜与轮动记录;
  5. 只有通过质量检查后才生成公开快照;
  6. 最后刷新网站和 App 使用的缓存。

这套顺序很重要。以前把抓取、计算和发布放在同一个请求里,任何一个环节变慢都可能导致网关超时。后来即使客户端显示超时,也必须先查看任务记录和通知日志,确认后台是否已经完成,不能盲目重复执行。

本地能用,不代表服务器能用

开发过程中,我测试过多类公开或免费数据源。最常见的情况包括:

  • 本地请求成功,云服务器连接却被重置;
  • 实时接口可用,历史接口需要更高权限;
  • 返回 HTTP 200,但内容为空或者数据日期已经过期;
  • 请求频率并不高,云服务器出口 IP 仍然被限流;
  • 同一个平台的日线接口可用,分钟线接口却不可用。

香港市场的数据采集尤其典型。我尝试过降低请求频率、拆成小批次、扩大批次间隔,并分别验证实时、分钟和日线接口。

台湾市场也出现过第三方库在本地可以使用,放到服务器后却被远端重置连接的情况。最后只能改用交易所提供的日线和最新行情接口。

这段经历改变了我的判断标准:

数据源是否可用,必须在真实服务器、真实时间窗口和真实股票池上验证。

单只 ETF 的一次请求成功,只能证明这个接口曾经响应过,不能证明它适合生产环境。

中国市场:价格与净值必须分开处理

中国 ETF 排行榜曾经出现过一个风险:候选 ETF 的动能很高,但单位净值缺失,导致溢价率没有完成验证。如果此时继续发布,排行榜可能纳入溢价明显过高的 ETF。

后来,我把净值处理独立出来,同步 unit_nav,并制定了几条规则:

  • 只使用在计算时点已经公布的单位净值;
  • 以最近一个已经完成的交易日为数据截止点;
  • 节假日可以向前寻找有限天数,但不能无限回退;
  • 排行榜前三名必须全部完成溢价验证;
  • 溢价超过策略阈值的 ETF 直接排除;
  • 前三名任何一只缺少有效净值时,暂停发布并通知管理员。

这种方式比“缺数据时换一个接口继续计算”更保守,但也更符合研究产品的边界:宁可明确显示待验证,也不要用猜测填补关键字段。

从接口调用变成数据发布流水线

经过多次问题处理,WZETF 的数据流程逐渐形成了几道质量门槛。

金融数据依次经过来源确认、完整性检查、快照生成和缓存刷新后公开发布

数据从采集、校验到公开发布的质量门槛示意图

来源约定

每个字段都要知道它来自哪里、代表什么,以及什么时间才可以使用。价格、净值、交易日期和公布日期不能全部混成一个“最新值”。

完整性检查

不能只检查文件是否存在,还要检查:

  • 数据是否属于目标交易日;
  • 股票池覆盖数量是否达到要求;
  • 价格是否为正数,是否存在异常跳变;
  • 排名前列需要的字段是否完整;
  • 排行榜和轮动记录是否使用同一份价格。

原子快照

新数据先写入临时版本,全部校验通过以后再替换当前快照。这样即使下载中途失败,线上用户看到的仍然是上一份完整数据,而不是一半新、一半旧的结果。

缓存失效与重建

修正源数据,并不代表用户已经看到了修正后的结果。排行榜缓存、轮动记录缓存、首页快照和 App 接口缓存,都必须按照依赖关系重建。

以前出现过文件已经修改正确,页面仍然显示旧数据的问题,原因就是缓存链路没有一起更新。

可审计状态

每次任务都应该记录数据日期、覆盖率、排除原因、发布时间和通知结果。出现问题后,至少要能回答三个问题:系统拿到了什么、为什么没有发布、用户最终看到了什么。

失败后不能只靠手工重跑

数据任务失败时,最危险的操作是立即重复点击“发布”。如果第一次请求只是前端超时,而后台仍在运行,第二次执行可能造成重复通知或重复写入。

数据事故发生后先审计,再预览修正结果,随后正式更正并恢复发布

数据任务失败后的审计、预览、更正和恢复流程

现在的处理方式分为四步:

  1. 先审计:查看任务日志、公开快照和通知记录,确认实际执行到了哪一步;
  2. 再预览:重新计算但不写入、不通知,对比原榜单和修正榜单;
  3. 正式更正:使用可以重复执行的发布流程,确保同一日期不会重复处理;
  4. 公开说明:如果用户已经收到错误结果,及时发送更正通知,说明原因和影响范围。

对于历史数据缺口,则使用独立的补齐脚本。脚本显示进度、控制请求间隔,遇到明确限流或者拒绝访问时立即停止,避免失败请求继续冲击数据源。

补齐完成后,还要重新计算轮动记录,而不是只修改价格文件。

为什么后来反而减少了采集次数

一开始,我认为采集越频繁越可靠。实际情况恰恰相反:如果产品只需要某个约定时点的研究快照,高频轮询反而会增加限流、网络故障和口径不一致的概率。

后来,不同市场都改为在明确时间窗口采集一次,或者分批完成采集。排行榜和轮动记录共用同一份经过验证的价格快照。

这样既降低了外部接口压力,也避免排行榜使用一种价格、轮动收益又使用另一种价格。

采集频率应该由产品的数据口径决定,而不是由接口允许调用多少次决定。

现在判断一个数据源,我会看什么

经历这些问题后,我不再只看免费额度和能否返回数据,而会评估以下方面:

维度 需要回答的问题
数据口径 是实时、延时、分钟线、日线,还是基金净值?
时间可得性 这条数据在策略计算时是否已经公布?
服务器可用性 云服务器出口 IP 能否稳定访问?
完整性 股票池覆盖率和目标日期是否符合要求?
限流方式 按分钟、按天、按 IP,还是按接口权限限制?
可恢复性 失败后能否补齐历史数据并重新计算?
可审计性 能否保存来源、时间、状态和排除原因?
使用边界 数据许可是否适合当前产品的展示方式?

免费数据源不是不能用于产品,而是不能把“免费”理解为“没有成本”。真正的成本会转移到验证、降频、重试、缓存、监控和人工处理上。

一些实际结论

第一,金融数据系统最重要的不是计算公式,而是输入数据在当时是否真实可得。

第二,关键数据异常应该阻止发布,而不是只在日志中留下一条警告。

第三,网站、App、轮动记录和通知应该来自同一份已经确认的快照,否则用户可能在不同入口看到不同答案。

第四,数据源一定会失败。可靠系统的目标不是永远不失败,而是在失败时不发布错误结果,并且能够快速定位、补齐和解释。

第五,对用户透明比掩盖问题更重要。研究产品建立信任,不只依靠收益曲线,也取决于出现错误后能否及时更正。

结语

从网站上线到多市场 App,WZETF 的数据处理经历了许多看起来很小、实际却会影响用户判断的问题。现在回头看,最大的变化并不是换了多少数据源,而是建立了一套更严格的发布观念:

数据可以暂时缺失,但不能未经验证就被当成结论发布。

未来还会增加新的市场和新的数据来源。但新增市场的第一步不会再是先接入一个接口,而是先定义数据口径、质量门槛、失败状态和恢复流程。

只有这样,新增的覆盖范围才是真正的产品能力,而不是新的不确定性。

警告重要说明

WZETF 提供 ETF 动能研究数据与历史回测展示,不构成个性化投资建议、交易指令或收益保证。