资讯动态

A股换手率数据清洗与口径校正:从1990到2024的实战指南

发布时间:2026/9/9 19:11:53 来源:尧图企业网站定制
先说我的判断做股票研究的人很多都踩过数据整理的坑。某券商研报里的数据、某个交易软件的指标口径经常对不上回测一跑全乱套。换手率这个指标看似简单——成交量除以流通股本但真要拉一个1990年到2024年、覆盖所有上市企业的完整序列中间全是细节。我前阵子刚好整理完一份这个时间跨度的换手率数据把全过程记录下来给准备自己做数据的同行一个参考。因为每只股票的上市日期不同所以这个数据集不是简单的全市场34年逐日面板而是按各自的上市时间截断。我统计了一下覆盖了5300多只A股标的最早的是1990年12月首批挂牌的那8只最晚的是2024年12月刚上市的次新股。单看时间跨度可能没感觉但你要想1990年那会儿全市场一天的成交额可能还不如现在一只中盘股一分钟的成交额。数据跨度拉这么长最大的挑战不是有没有数据而是数据的口径在34年里变了好几次。1. 换手率数据为什么值得单独做一版不是简单算个除法那么简单先把这个指标本身说透。换手率的标准公式是当日成交量除以当日流通股本代表这只股票有多少比例的流通筹码在今天换了主人。听起来简单但作为研究指标它有几个别的指标替代不了的作用。第一换手率是判断股票活跃度最直接的代理变量。成交额会被股价放大——茅台涨到1700块一手就17万成交额看着吓人但实际换手的股数可能并不多。换手率剔除了股价绝对水平的影响直接反映市场参与者对这个标的的关注度。同样是5个亿的成交额一只5块钱的票和一只200块钱的票换手率能差出十几倍市场意义完全不一样。第二换手率是许多因子模型里流动性因子的原材料。异质波动率、Amihud非流动性指标、个股波动率、最大日收益率这些经典量价因子构建的时候基本都要用换手率做基准或者做过滤条件。没有一套干净的历史换手率序列这些因子全都跑不了。第三换手率在行为金融研究里是投资者情绪的度量。A股市场散户占比高换手率长期高于成熟市场这里面既有制度因素也有情绪因素。研究市场情绪周期、波动聚集效应、崩盘风险换手率都是绕不开的变量。但关键问题来了从Wind、同花顺、Tushare这些终端直接导出的换手率数据往往看着能用实际上隐患很多。最大的问题是历史口径不一致。早年交易所披露的流通股本不是现在这个定义中间经历过股权分置改革、限售股解禁、机构配售股上市每一次股本结构变化换手率序列都会出现断裂式跳变。你如果不处理这些跳变直接拿去做回测策略很可能在股改完成、大盘股集中解禁的那几个时间点出现莫名其妙的异常收益查了半天不知道问题出在哪。所以我做这个数据集时给自己定的标准是三条覆盖全、口径统一、可复现。覆盖全意味着1990年至今A股所有上市企业的所有交易日都要有口径统一意味着不管历史上股本结构怎么变换手率的计算基准都要校正到同一套规则可复现意味着拿到数据的人能清楚地知道每一列是怎么算出来的不会一遇到异常值就抓瞎。2. 数据集的字段结构和时间口径拿到的每一列都有出处很多人下载完数据直接就开跑根本不看字段说明结果拿总股本换手率当流通股本换手率用写论文被审稿人一问就露馅。我这里把最终交付的字段结构完整列出来每一列为什么存在、怎么算的都交代清楚。字段名含义计算说明symbol证券代码6位数字代码不带市场后缀如需区分沪深可自行拼接.SH/.SZtrade_date交易日期YYYY-MM-DD格式只保留实际交易日非交易日不在序列中short_name股票简称该交易日的简称快照含ST、*ST标识industry所属行业按申万一级行业分类用于分组统计turnover_rate日换手率当日成交量/当日流通股本×100%注意是流通股本口径turnover_rate_total总股本换手率当日成交量/当日总股本×100%用于对比分析volume成交量当日成交股数手×100单位股amount成交额当日成交金额单位元circ_mv流通市值当日流通股本×当日收盘价单位元total_mv总市值当日总股本×当日收盘价单位元listing_date上市日期用于识别次新股区间is_st是否ST1ST或*ST0正常交易辅助过滤极端样本把两个换手率口径同时放进去是故意为之。我见过一个做得挺漂亮的横截面研究用的换手率数据其实混着两种口径——部分股票是流通股本算的部分因为数据源缺失用了总股本补齐结果因子分析里出现了严重的分组误差。所以我在交付时干脆两个口径都给宁可让用户自己选也不能替他做决定。时间口径上有一个容易忽略的点早年的交易制度跟现在不一样1990-1995年那会儿没有严格的10%涨跌停限制也没有T1制度最早是T0所以最早的换手率天然偏高。这不算数据错误但做跨时期对比时必须知道这个制度背景否则你会以为1993年的市场疯掉了其实是规则不同。上市区间的处理逻辑是这样每只股票从上市日次日开始纳入数据上市首日本身不纳入。原因是A股新股上市首日不设涨跌幅限制注册制前是44%涨停限制首日换手率动辄百分之七八十甚至更高跟正常交易日完全不是一个分布放进日度面板里会严重扰动横截面统计量。但如果用户需要研究炒新股现象我把上市日期字段提供了自己过滤一下就能把首日数据捞回来。3. 数据清洗和口径校正三分靠采集七分靠对账3.1 从公开数据源拉取到统一入库的完整链路我处理数据主要依赖Tushare Pro的接口和聚宽、米筐等平台的历史快照再配合CSMAR和Wind的抽查校验。流程通常是这样的先用Tushare Pro的daily_basic接口拉全部历史日线这个接口自带换手率字段turnover_rate但它给的是流通股本口径而且早年数据存在大量缺失。再把聚宽的行情数据和米筐的复权因子数据跑一遍把缺失的部分补上来。最后用CSMAR的数据库做抽样比对重点抽查1997-2005年这段数据质量最不稳定的区间。整个流程跑完大约需要几个通宵的机器时间但真正麻烦的不是拉数是拉完之后的对账。我按年份抽样每年随机抽10只股票把从Tushare、聚宽、CSMAR三个源拿到的换手率序列并排列出来逐日比对。只有三个源完全一致才放行有任何偏差就整段标记出来人工排查。实际跑下来2005年之前的旧数据出错率明显偏高尤其是1998-2001年间刚好赶上数据披露规范化之前不少股票复权因子算出来是错的直接导致成交量数据偏差换手率自然跟着错。3.2 停牌日、无成交日与缺失值的区分处理这是最容易被忽略的坑。很多数据源对停牌日的处理是直接不返回这一行你合并面板时如果按左连接合并停牌日会被静默丢掉但如果你按笛卡尔积展开所有股票所有交易日再join停牌日对应的是NaN。这两种做法对后续计算的差别是巨大的。我在处理时做了三个分类停牌日当日无交易换手率为0标记为停牌。正常交易日但无成交这种极罕见A股几乎不存在但不排除早期的部分股票换手率为0标记为无成交。数据源缺失当日实际有交易但没拿到数据标记为NaN。三个分类的后续处理完全不同。停牌日的0是真实值做任何统计时都该保留数据缺失的NaN则必须想办法补。我见过有人把所有NaN直接填0结果把一堆缺失值变成了零换手做出来的换手率分布图左下角突然堆起一座山真实情况根本没这么高。3.3 股权分置改革与限售股解禁的跳变校正换手率计算的分母是流通股本流通股本本身是随时间变化的。对A股而言最剧烈的变化来自两件事2005-2007年的股权分置改革以及此后持续不断的限售股解禁。举个例子一只股票股改前流通股可能只有总股本的30%股改完成后限售股逐步解除限售流通股本在几个月内从3亿股涨到10亿股。分母变了3倍多换手率如果照搬原始数据会看到一条断崖式下跌的曲线——但这不是因为交易变清淡了纯粹是分母变了。我处理时用了可比口径校正以最新股本结构为基准对历史换手率做向后复权的调整把每一次股本变动导致的跳变全部抹平。具体做法是计算一个流通股本扩张倍数序列然后把历史成交量除以最新流通股本得到基于当前流通股本的等效换手率。这样做的好处是整个时间序列前后可比不会出现因为股改导致的假跳变坏处是历史换手率的绝对值与现代口径不完全一致——但研究本来就不该把1995年的换手率和2023年的换手率直接比大小。当然我同时保留了原始口径的换手率字段名是turnover_rate_raw方便那些需要原始口径做对照的用户。3.4 复权因子的边界问题涨跌停板与一字板场景换手率计算本身不需要复权——成交量不受除权除息影响但如果你把换手率和股价数据放在一起做研究股价的复权口径就得仔细考虑。这里有个特别隐蔽的坑ST股的连续一字跌停。一只ST股跌停时卖单排队几十万手但成交量可能只有几百手。这时候换手率约等于0但如果你的数据里这只股票当天涨跌幅显示为-5%ST股跌停限制5%价格看起来还能正常交易。问题在于如果你用涨跌幅来识别一字板你得同时结合换手率——一字跌停板涨跌幅触发下限换手率极低。只靠单一指标很容易误判。我专门给这类情况加了一列is_limit_one_word是否一字板识别逻辑是当日收盘价触及涨跌停价且换手率低于某个阈值默认0.5%。实际效果验证下来这个标记在做A股跌停板打开后的反弹策略、次新股开板策略时有奇效省了后面用的人大量重复工作。4. 换手率数据的典型研究应用和实操注意事项4.1 因子构建中的标准化细节拿到干净的换手率数据后最常见的用途是构建流动性因子。我给几个实操建议月度频率上用当月日均换手率取对数再按行业和市值做中性化处理得到 residual 再做z-score标准化。直接拿原始换手率做横截面排序会出问题——因为换手率和市值高度负相关你排序出来的高换手组几乎全是小盘股买进去等于在小市值因子上做了一次超额暴露。对冲这个风险的标准做法是每个月末对换手率做横截面回归控制变量取对数市值和行业虚拟变量取残差后再排序。我测试过处理前后的因子IC有不少区别不放心的可以自己在数据上验证一下。此外换手率数据里偶尔会出现极端值——某些小盘股被资金炒作时换手率能冲到30%甚至50%这种样本在构建因子时建议做MAD中位数绝对偏差缩尾处理。MAD比均值标准差稳健不会让少数极端炒作样本把整个因子分布拉偏。4.2 换手率与波动率、收益率的联动特征老股民都知道天量见天价换手率数据可以把这个朴素经验量化。回测1990年以来A股的数据可以看到一个清晰的规律全市场日均换手率超过某个阈值大约在3%-4%之间时未来20个交易日的市场平均收益倾向于为负而市场极度低迷、换手率跌破1%时未来一年出现大级别行情的概率显著升高。这本质上是一个均值回归逻辑——换手率太高说明情绪过热太低说明恐慌出清。但这里要强调一点这个规律用在指数层面比较稳健用在个股层面很不稳定。原因是单只股票的换手率受事件驱动太强——并购重组、业绩暴雷、股东增持都能让个股换手率瞬间飙升但这种飙升并不都意味着过热。所以如果你要做个股层面的择时建议配合换手率的历史分位数使用而不是用绝对阈值。4.3 新股上市初期的换手率特征次新股是换手率研究的特殊样本区间。A股新股上市初期换手率天然畸高注册制之前的新股上市首日有44%涨停限制导致很多新股开板前换手率被锁住注册制后首日不设涨跌幅首日换手率经常百分之六七十随后几天快速回落到正常水平。这个从畸高到正常的过程不同股票持续的时间长度差异很大研究次新股炒作周期的可以基于这个数据集算一个开板换手率衰减系数。具体用法对每只次新股计算上市后第1、2、3、5、10日的换手率形成一个衰减曲线。把衰减速度进行分类衰减极快的通常说明筹码锁定良好或炒作结束衰减极慢的说明持续有资金交换往往对应游资接力。结合龙虎榜数据一起看能识别出几种典型的次新股炒作模式。4.4 行业轮动研究中的换手率偏离度做行业轮动的朋友可以试试把换手率数据用在行业拥挤度的度量上。方法很简单对每个申万一级行业计算当日行业总换手率相对过去60日平均换手率的偏离度偏离度超过2倍标准差时标记为拥挤状态。历史回测显示行业换手率偏离度进入极值区域后未来5-10个交易日该行业跑赢全市场的概率会显著下降——也就是拥挤交易的负反馈效应。用这个指标做行业配置的减仓信号比单纯看估值分位要灵敏得多。估值的修复是慢变量换手率的飙升是快变量快变量对短期择时的指导意义更强。5. 数据验证和常见陷阱我的踩坑记录5.1 数据源之间的标准不统一问题我最初做第一版时在2015年股灾期间的数据上发现了明显异常同一只股票Tushare给的数据显示当天换手率8.7%聚宽给的却是9.9%差距大到完全不可忽略。排查后发现原因2015年6月-7月很多股票停牌复牌后连续跌停部分数据源用的是按总股本计算的换手率部分用自由流通股本计算还有的干脆用流通股本中的实际流通部分——在极端行情下这些口径的差异会被放大到非常夸张。我最后把2015-2016年的所有数据逐个源交叉验证统一按交易所披露口径校准才把这个问题解决。这种口径不一致问题最恐怖的点在于它只会在极端行情下暴露出来普通时间段三种算法算出来的结果相近你根本发现不了。等你拿数据去做压力测试结果全线崩盘再回头查才发现是数据底层就错了。所以我在最终版数据里加了数据源标记字段source虽然是混合来源但每个时间段的来源标注得清清楚楚。5.2 历史行情数据中的跳空谬误另踩过一个坑某只股票2010年3月的数据里换手率连续一周显示为0.0001%左右看着像交易极其清淡但成交额却不低。排查后发现是当天成交量数据单位错位——源数据把股和手搞混了1手100股导致成交量被缩小了100倍。换手率成交量/流通股本分子错了100倍数据全错。这种单位错位在早年手工录入时代特别常见哪怕后期电子化数据迁移时的手误也偶有发生。应对方法是在数据集成流程里加入一套常识校验规则当日换手率超过30%时告警连续5日换手率低于0.01%但成交额大于1000万时告警成交量变化率超过前20日均值10倍时告警。这套规则帮我抓出了好几处源数据错误。5.3 银行、证券等特殊行业的换手率解读最后特别提醒一下特殊行业的换手率解读问题。银行股、石油股这类大权重股流通股本极其庞大日常换手率经常在0.2%-0.5%之间徘徊看起来就像一潭死水但这不是股票没有人气是盘子太大——一天的成交额几十亿甚至上百亿摊到数万亿的流通股本上换手率当然高不起来。小盘题材股就相反流通盘可能只有几亿股一天换手率飙到20%轻轻松松。所以在做全市场横截面研究时我习惯对换手率先做行业中性化处理或者按市值分组后再比较组内相对位置而不是直接跨行业比绝对数值。你拿一个银行股0.3%的换手率和一个次新股15%的换手率放在同一个模型里跑模型会以为银行股极度冷门但这是结构性差异不是情绪或流动性差异。5.4 数据集的版本管理加了一列血液改了一版皮肤这版数据做完后我没有一次性了事而是把源数据和衍生计算脚本分开管理每次修订都标注版本号。因为数据这东西最容易出的问题不是当时错了而是后来的修订覆盖了之前的正确结果等再被别人用的时候根本不知道这个数是谁在什么时候改的。我的做法是原始数据落库后只读不写所有清洗逻辑都写成脚本重跑每一步都输出一份checkpoint文件最后生成的数据集带hash校验值。这样任何一个数变了对不上号往回追一步就能定位到是清洗逻辑的变化还是源数据的更新。做这个数据集前后花了很长时间但做完回头看我认为最有价值的不是数据本身而是把换手率背后的口径差异、制度背景、异常模式理清楚了。数据这东西如果你不知道它哪里可能出错就永远不敢放心地用如果你知道查过了哪里、还差哪里用起来心里才踏实。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价