2. 行业指数数据获取与清洗
复权与对齐的质量,首先取决于进入复权环节之前的原始数据是否干净、口径是否统一。行业指数日频数据通常来自两类渠道:一类是Wind、Choice、同花顺iFinD等商业数据终端,另一类是交易所网站、中证指数官网、国证指数官网等公开接口。无论来源如何,导出的原始表几乎不可能直接用于复权计算——缺失交易日、重复记录、异常价格、停牌标记不规范等问题普遍存在。本节的任务,就是把一份"能看"的行情表,加工成一份"能用"的原始数据表。
一、先明确目标表结构
在动手取数之前,应先确定清洗后的目标表应具备哪些字段。行业指数日频数据的最小可用字段集通常包括:指数代码、交易日期、开盘价、最高价、最低价、收盘价、成交量、成交额,以及一个明确的交易状态标记。若后续需要计算全收益或进行分红再投资,还应保留成分股股息率或指数类型说明。字段命名建议统一为英文小写下划线形式,例如 index_code、trade_date、close、volume、trade_status,避免不同来源合并时出现"收盘价/close/CLOSE"三列并存的情况。
日期字段必须统一为 YYYY-MM-DD 格式的日期类型,而不是字符串或带时间的日期时间。价格字段统一为浮点数,成交量与成交额明确单位(如手、股、元、万元),并在表级元数据中记录单位约定。这一步看似琐碎,却是后续对齐不出错的前提。
二、缺失值的识别与处理
行业指数日频数据的缺失分两种性质,处理方式完全不同。第一种是非交易日缺失:周末、法定节假日、交易所临时休市,这些日期本就不该有记录,不应填补,只需保证交易日历完整即可。第二种是交易日缺失:某交易日应有数据却为空,可能源于接口限流、导出截断、指数当日无成交或数据源本身缺漏。
处理时先构建一份权威交易日历(可用中证指数官网公布的交易日历,或以上证指数交易日为准),将原始数据与日历做左连接,凡日历中有、原始表中无的交易日,标记为待核查。对于价格类字段,若确认是指数当日无成交导致的缺失,可按"前收盘价延续"处理,即用上一有效交易日的收盘价填充,同时将 trade_status 标记为"无成交";若属于数据源缺漏,则应回到源头补取,而不是用插值掩盖。成交量、成交额缺失时不宜用前值填充,应保留为空并标记,避免在后续统计中虚增流动性。
三、重复日期与异常价格
重复记录常见于多次导出拼接、接口分页重叠等场景。判断标准是"同一指数代码 + 同一交易日期"应唯一。去重时不能简单保留第一条,而应比较重复行的价格与成交量:若完全一致,任取一条;若不一致,优先保留数据源权威版本(如交易所官方口径),并记录被丢弃行的来源,便于审计。
异常价格主要包括:收盘价为零或负、单日涨跌幅超过合理阈值、最高价低于最低价、收盘价落在当日最高最低价区间之外。对行业指数而言,单日涨跌幅超过±11%(考虑指数成分股涨跌停与权重分布)即应触发核查。处理方式不是直接删除,而是先标记、再判断:若为数据录入错误(如小数点错位),按相邻交易日价格量级修正;若为指数编制调整或成分股更换导致的跳变,应保留真实值并在备注中说明,因为这类跳变在复权时需要通过因子调整来吸收,而非在清洗阶段抹平。
四、停牌标记的规范化
停牌标记是复权对齐中最容易被忽视、却直接影响对齐结果的字段。不同数据源对停牌的表述五花八门:"停牌""S""停牌一天""全天停牌",甚至用成交量为零隐式表达。清洗时应统一映射为枚举值,例如 normal(正常交易)、suspended(全天停牌)、no_trade(无成交但未停牌)、halt(临时停牌)。映射规则应写入配置文件,保证可复现。
需要特别注意的是:行业指数本身通常不会"停牌",停牌标记更多出现在成分股层面。若原始数据是指数行情,停牌字段往往为空;若数据来自成分股加权合成,则需保留成分股停牌信息。清洗阶段应明确当前表的粒度是指数级还是成分股级,避免把成分股停牌标记错误地挂到指数行上。
五、形成可复权对齐的原始数据表
完成上述四步后,应输出一张结构稳定、口径清晰的原始数据表。建议在表级附加一份清洗日志,记录:数据来源与导出时间、交易日历版本、缺失值填补条数与方式、去重条数、异常价格标记条数、停牌标记映射规则版本。这份日志是后续复权结果可追溯、可复现的关键。
下面给出一个可直接参考的清洗配置样例,用于把不同来源的停牌表述映射为统一枚举:
trade_status_map:
"正常": normal
"交易": normal
"停牌": suspended
"全天停牌": suspended
"S": suspended
"临时停牌": halt
"无成交": no_trade
"": no_trade # 空值且成交量为0时按无成交处理
price_rules:
close_min: 0.01
daily_return_alert: 0.11 # 超过±11%触发人工核查
fill_missing_close: prev_close # 仅限确认无成交的交易日
清洗完成后,应做一次完整性校验:交易日历中的每个交易日是否都有对应记录;同一指数代码+日期是否唯一;收盘价是否全部大于零;trade_status 是否全部落在枚举集合内。四项校验全部通过,这张表才具备进入复权与对齐环节的资格。需要强调的是,清洗阶段的目标是"还原真实、标记不确定",而不是"让数据看起来完整"——后者往往会在复权时以更隐蔽的方式反噬结果。