2. 数据源采集偏差排查

板块资金数据的第一道偏差往往不是出在计算模型,而是出在“数据进门”的那一刻。交易所行情与资金流接口在采集环节存在三类高频问题:字段缺失、时间戳错位、复权处理不一致。它们的共同特征是——入库后的数据看起来“有值”,但值与原始报文对不上。因此本节的核心方法不是猜,而是拿原始报文与入库数据逐字段对账,把偏差定位到采集链路的某一环。

一、先建立“采集链路”的对账视角

一条板块资金数据从接口到入库,通常经过:接口请求 → 原始报文落盘 → 解析映射 → 字段清洗 → 复权/单位换算 → 入库。偏差可能发生在任意一环,但对账时只需要两个锚点:原始报文(接口返回的原始 JSON/二进制/文本)和入库记录(数据库中的最终值)。中间环节的差异,通过字段级比对反推。

实操中建议保留原始报文快照,至少包含请求参数、响应体、响应时间、HTTP 状态码。没有原始报文,后续所有排查都会退化为“凭经验猜”。下面这张图展示了采集链路中三类偏差的典型发生位置与对账锚点关系:

采集链路与三类偏差发生位置 接口请求 行情/资金流API 原始报文落盘 JSON/文本快照 解析映射 字段名→列名 清洗与换算 单位/复权处理 入库记录 数据库最终值 锚点A:原始报文 锚点B:入库值 偏差① 字段缺失 报文有 net_amount 字段 解析映射未覆盖 → 入库为 NULL 或接口分页截断导致尾部缺失 发生在解析映射 偏差② 时间戳错位 接口返回 UTC 秒级时间戳 入库按本地时间解析 → 偏移8小时 或跨日归属错误(T日/T-1日) 发生在清洗换算 偏差③ 复权不一致 行情接口给不复权价 资金流按前复权计算 → 量价错配 除权日前后资金流突变 发生在复权处理 对账方法:锚点A(原始报文) ↔ 锚点B(入库值)逐字段比对 ① 字段级:报文键名是否存在、值类型是否一致、NULL 是否被误填为 0 ② 时间级:报文时间戳单位(秒/毫秒)、时区、交易日归属是否与入库一致 ③ 价格级:复权方式(不复权/前复权/后复权)、除权日、单位(元/万元)是否统一

二、字段缺失:先分清“没给”还是“没接住”

字段缺失有两种性质完全不同的情况。第一种是接口本身没返回该字段,例如某资金流接口在非交易时段只返回基础行情字段,net_amount、buy_volume 等字段整体缺席;第二种是接口返回了,但解析映射没接住,例如报文键名从 netAmount 改成了 net_amount,映射表未更新,入库列被写成 NULL 或默认 0。

区分方法很直接:打开原始报文,搜索目标字段键名。若报文里没有,属于接口侧缺失,需要检查请求参数(是否漏传 fields 白名单、是否分页未取全);若报文里有而入库为 NULL/0,属于解析侧缺失,检查映射配置与类型转换。特别注意“NULL 被填成 0”这种隐性缺失——它不会报错,但会让资金流统计把缺失当成零流入,直接污染板块汇总。

# 示例:对比原始报文与入库记录(示例数据,非实测)
原始报文片段:
{"code":"BK0475","trade_date":"2024-06-14",
 "net_amount":-125800000,"buy_volume":3200000,
 "sell_volume":4100000,"close":1024.35}

入库记录:
code=BK0475, trade_date=2024-06-14,
net_amount=0, buy_volume=3200000,
sell_volume=4100000, close=1024.35
# 判断:net_amount 报文有值(-1.258亿),入库为0 → 解析映射缺失或类型转换失败

三、时间戳错位:单位、时区、交易日归属三层检查

时间戳错位最常见的表现是“数据整体平移”。排查按三层走:第一层看单位,接口给的是秒级还是毫秒级,入库字段是 DATETIME 还是 BIGINT,混用会导致 1970 年或 55000 年这类离谱值;第二层看时区,接口常返回 UTC 时间戳,若直接按本地时间(UTC+8)解析,所有记录会偏移 8 小时,跨日数据会被归到错误交易日;第三层看交易日归属,A 股 15:00 收盘后的资金流数据,部分接口以“清算完成时间”打戳,可能落到次日凌晨,若按自然日入库,T 日数据会被记到 T+1 日。

验证手段是取一条已知交易日的记录,把报文时间戳按不同假设还原,与交易所公布的交易日期比对。例如报文时间戳 1718352000(秒级),按 UTC 解析为 2024-06-14 08:00:00,按 UTC+8 解析为 2024-06-14 16:00:00,两者交易日相同但时刻不同;若该接口实际是毫秒级 1718352000000,误按秒解析会得到 56392 年的错误值。这类错误在入库后表现为“时间字段异常大/异常小”,是很好的排查线索。

四、复权处理不一致:量价必须同源同口径

复权偏差的根源是“行情价”和“资金流量”用了不同复权口径。资金流 = 成交额 × 方向,成交额依赖价格;若行情接口返回不复权收盘价,而资金流模块按前复权价计算,除权日前后就会出现量价错配:股价因除权下跌 30%,但资金流仍按除权前价格计算成交额,导致板块资金流在除权日出现虚假的巨额流出。

排查时先确认三个口径:行情价是不复权、前复权还是后复权;资金流接口的成交额字段是原始成交额还是复权成交额;板块成分股的复权因子是否与个股行情一致。三者必须统一。实操中建议在采集层显式记录 adjust_type 字段(如 none/qfq/hfq),入库时与价格字段绑定,避免下游混用。除权日附近的数据要单独抽查:取除权日前一交易日与除权日当天,对比板块资金流是否出现与除权比例不符的突变,若有,基本可判定复权口径不一致。

对账时优先比对“可复现的最小样本”:选一个板块、一个交易日、一条记录,把原始报文、解析中间值、入库值三列并排,逐字段标注差异。小样本对清楚,再放大到全量,比直接跑全量比对更容易定位根因。

五、把排查固化为可复用的对账清单

三类偏差的排查动作可以固化为一张采集对账表,每次接入新接口或数据异常时按表执行:

检查项 对账对象 判断依据 典型处置
字段完整性 报文键名 vs 入库列 报文有值、入库 NULL/0 补映射、修类型转换
接口侧缺失 请求参数 vs 返回字段 报文整体缺字段 补 fields 白名单、取全分页
时间戳单位 报文时间戳 vs 入库时间 年份异常(1970/5万年后) 统一秒/毫秒解析
时区与交易日 UTC 解析 vs 本地解析 整体偏移 8 小时或跨日 显式指定时区、按交易日归属
复权口径 行情价 vs 资金流成交额 除权日资金流突变 统一 adjust_type 并绑定入库

采集偏差排查的价值在于“把问题挡在入库之前”。字段缺失、时间戳错位、复权不一致这三类问题,只要保留原始报文、坚持锚点对账、把口径显式化,就能从“数据看起来不对”快速收敛到“哪一环、哪个字段、什么原因”,为后续的资金流计算与板块汇总提供干净输入。