4. 金融数据源概览

构建Point-in-Time(PIT)数据集的第一步,不是写代码,而是把“数据从哪来、多久更新一次、覆盖谁、怎么拿到”这四件事彻底想清楚。很多回测失真、因子失效、模型过拟合,根源并不在算法,而在于对数据源属性的误判。本节把金融数据源拆成五类:财报、行情、公告、宏观、另类数据,逐一梳理其来源、频率、覆盖范围与获取方式,并给出PIT视角下的关键判断标准。

一、核心原理:五类数据源的PIT属性差异

PIT的核心要求是:在任意历史时点t,只能使用t时刻真实可获得的信息。不同数据源的“可获得时点”差异极大。财报有报告期与披露日的分离;行情有交易所时间戳与本地接收时间的差异;公告有发布时刻与传播延迟;宏观数据有初值、修正值、季节调整版本;另类数据则往往带有采集延迟和样本偏差。理解这些差异,是构建可信PIT数据集的前提。

五类金融数据源的PIT时间轴与可获得性 报告期/事件发生 实际可获得时点 财报 季度/年度 披露日+1 行情 毫秒/分钟/日 实时/准实时 公告 事件驱动 发布时刻 宏观 月度/季度 初值发布日 另类 不定/高频 采集+清洗后 PIT关键判断: 1. 财报:报告期 ≠ 披露日,必须用披露日+1作为可用起点 2. 行情:交易所时间戳与本地接收时间可能相差数秒至数分钟 3. 宏观:初值、修正值、季节调整版本必须分别记录,不可混用

二、方法流程:五类数据源的获取与PIT化处理

获取数据不是终点,PIT化处理才是关键。以下按数据源类型给出标准处理流程。

  • 财报数据:来源为交易所披露平台、Wind、Choice、Tushare等。频率为季度/年度。覆盖A股全市场及港股、。获取方式包括API、数据库导出、爬虫。PIT处理要点:记录report_date(报告期)与announce_date(披露日),可用时点取announce_date + 1。
  • 行情数据:来源为交易所Level-1/Level-2、券商柜台、Yahoo Finance、AKShare等。频率从Tick、分钟到日线。覆盖全球主要交易所。获取方式为API推送、历史数据下载。PIT处理要点:区分交易所时间戳与本地接收时间,日线数据需确认是否包含当日收盘后信息。
  • 公告数据:来源为巨潮资讯、交易所网站、公司官网。频率为事件驱动。覆盖上市公司全部强制披露。获取方式为爬虫、RSS、API。PIT处理要点:记录精确到分钟的发布时间,避免使用“日期”粒度导致前视偏差。
  • 宏观数据:来源为国家统计局、央行、Wind、FRED。频率为月度/季度。覆盖GDP、CPI、PMI、利率、货币供应等。获取方式为API、网页下载。PIT处理要点:区分初值、修正值、季节调整版本,记录release_date而非period_date。
  • 另类数据:来源为卫星图像、信用卡流水、招聘网站、社交媒体、供应链物流。频率不定,从日到季度。覆盖范围因供应商而异,常存在样本偏差。获取方式为商业采购、合作、爬虫。PIT处理要点:记录采集时间、清洗时间、供应商交付时间,三者取最晚作为可用时点。

核心原则:任何数据字段都必须附带一个“可用时点”字段(available_time),该字段是PIT数据集的灵魂。没有它,回测就是在用未来信息。

三、案例/场景:一个财报PIT数据集的构建片段

假设我们要构建A股某公司2020—2023年的季度营收PIT序列。原始数据来自Tushare,包含ts_code、end_date(报告期)、ann_date(披露日)、revenue。直接按end_date排序会引入前视偏差,因为2020年Q1的报告期是3月31日,但披露日可能是4月28日。在4月28日之前,市场并不知道这个营收数字。

import pandas as pd

# 原始数据示例
df = pd.DataFrame({
    'ts_code': ['000001.SZ']*4,
    'end_date': ['2020-03-31','2020-06-30','2020-09-30','2020-12-31'],
    'ann_date': ['2020-04-28','2020-08-25','2020-10-27','2021-04-20'],
    'revenue': [100, 210, 320, 450]
})

# PIT化:可用时点 = 披露日 + 1个交易日(保守处理)
df['available_time'] = pd.to_datetime(df['ann_date']) + pd.Timedelta(days=1)

# 查询2020-09-01时点可用的最新营收
query_time = pd.Timestamp('2020-09-01')
available = df[df['available_time'] <= query_time]
latest = available.sort_values('available_time').iloc[-1]
print(latest[['end_date','revenue','available_time']])
# 输出:2020-06-30, 210, 2020-08-26

这个片段展示了PIT数据集的核心操作:在任意查询时点,只保留available_time小于等于该时点的记录,再取最新一条。这样,2020年9月1日只能看到Q2的210,而看不到Q3的320。

四、误区/复盘:常见的数据源误判与修正

误区1:用报告期代替披露日。这是最普遍的前视偏差来源。修正方法:始终以ann_date或release_date为准,并加1个交易日缓冲。

误区2:忽略宏观数据的修正值。GDP初值与修正值可能相差0.5个百分点以上。修正方法:分别存储初值、修正值,并在PIT查询时只使用当时已发布的版本。

误区3:另类数据直接按采集日使用。供应商交付可能延迟数天至数周。修正方法:记录collection_time、delivery_time,取最晚者作为可用时点。

误区4:行情数据混用不同来源。不同交易所的收盘时间、时区、复权方式不同。修正方法:统一时区与复权口径,并记录数据来源标识。

数据源 典型来源 频率 覆盖范围 获取方式 PIT关键字段
财报 交易所、Wind、Tushare 季度/年度 A股/港股/ API、数据库 ann_date
行情 交易所、券商、AKShare Tick/分钟/日 全球主要交易所 API推送、下载 exchange_ts
公告 巨潮、交易所网站 事件驱动 上市公司 爬虫、RSS publish_time
宏观 统计局、央行、FRED 月度/季度 国家/地区 API、网页 release_date
另类 卫星、信用卡、招聘 不定/高频 因供应商而异 采购、合作 delivery_time