news 2026/10/16 5:04:34

32年信息不对称面板数据构建:Amihud、流动性比率与反转指标全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
32年信息不对称面板数据构建:Amihud、流动性比率与反转指标全解析

简介:1991-2022年沪深北A股上市公司信息不对称程度测算数据,可通过文档内的百度网盘链接及提取码获取。压缩包仅含1个docx说明文件(约70KB),但网盘内提供59534条上市公司年度面板数据,涵盖流动性比率(LR)、非流动性比率(ILL)、收益率反转(GAM)及综合指数ASY1、ASY2等7个字段,并附Stata计算代码、Excel结果文件,以及2007-2021年超2.8GB原始数据,便于用户复现测算过程。两个综合指数无本质差别,可根据实证回归的显著性择优使用。该数据时间跨度长、样本量大,能为固定效应回归、稳健性检验和异质性分析提供充分支撑。数据测算思路引自金融科技与企业全要素生产率等权威文献,已有231人学习下载,适合金融、会计、经济学研究者用于融资约束、信息不对称与公司金融等主题的实证分析,也可作为本科或研究生毕业设计的基础数据。

1. 一份横跨32年的信息不对称面板数据,到底在衡量什么

做资产定价或公司金融实证的人,大概率被同一个问题卡过:信息不对称程度怎么量化?问卷不可得,内幕交易数据更不可得,能落地的就是各种基于市场微观结构的代理指标。标题里这份数据集,说白了就是把学术界用得最普遍的三种口径——流动性比率、非流动性比率、收益率反转指标——在1991到2022年间逐月算好,形成一份可以直接拿去回归的面板数据。适合做实证论文、做因子测试,或者给量化策略补充一个风格暴露维度的从业者。

这份数据真正值钱的不是那几十行指标,而是32年窗口里对制度变化的处理,比如涨跌停制度、股权分置改革、做空机制出现,这些都会让同样一条公式在不同年份算出完全不同性质的东西。文章不代下载,也不假装见过压缩包内容,只把它拆成可复现的技术问题:三个指标的学术定义、从行情数据重建的最小代码、时间维度上的口径一致性处理,以及最容易翻车的几个坑。

2. 三个口径:流动性比率、非流动性比率与收益率反转的计算逻辑

2.1 非流动性比率:Amihud指标为什么是学术和实务的默认口径

非流动性比率通常直接称之为 Amihud 指标,定义为日收益率绝对值与日成交金额之比。公式是:

[ ILLIQ_{i,t} = \frac{|R_{i,t}|}{VOLD_{i,t}} ]

其中 (R_{i,t}) 是股票 i 在第 t 日的收益率,(VOLD_{i,t}) 是当日成交金额。直觉很朴素——每成交一块钱,股价动得越厉害,说明这个股票的流动性越差,做一笔大单对价格的冲击越大。反过来,冲击越大,知情交易者越容易藏住自己的头寸,信息不对称程度越高。

这个指标在1991到2022这个时间窗口里有个天然优势:只需要日度收益率和日度成交额,前者任何行情源都有,后者至少在1991年以后的主流交易所披露里是连续的。相比高频价差模型(比如 Roll 模型、Kyle 模型),Amihud 不需要逐笔成交数据,这在早期市场是不可得的。另一个实际好处是它对涨停板的存在有一定容忍度——虽然涨跌停会让收益率失真,但成交额通常还在,后面会专门说怎么处理。

计算时有几个参数直接决定结果形态。第一是成交金额的单位,常见的做法是用万元或百万元为单位而不是元,否则 ILLIQ 的数值会小到完全没法看。第二是缺失值的处理,停牌日当天收益率和成交额实际上不存在,不能简单粗暴地填 0,那样会把 ILLIQ 直接拽到 0,产生大量伪流动性好的样本。第三是在截面回归里要不要对原始 ILLIQ 取对数或开根号,因为原始值右偏严重,不做变换的话,尾部几个异常值会主导整个回归。我个人习惯是用 (\ln(1+ILLIQ)) 做变换,既保留0值样本,又压缩尾部。

另外一个容易被忽略的是测度频率。日度 ILLIQ 算出来后,通常要合成月度或年度变量。月度合成用简单算术平均最稳妥,与文献保持一致,方便后续和其他研究对比。也有人用市值加权平均,那是另一个逻辑,如果要做因子,建议保持简单平均,否则结果不好解释。

2.2 流动性比率:从回归系数到周度汇总

流动性比率与 Amihud 是“一正一反”的关系。常见的定义来自 Amivest,公式为:

[ LR_{i,t} = \frac{\sum P_{i,j} V_{i,j}}{\sum |\Delta P_{i,j}|} ]

即一段时间内成交金额之和除以价格绝对变化量之和。分子是多大的资金量在参与交易,分母是这个资金量造成的价格扰动,比值越大,说明单位价格波动吸收的资金越多,流动性越好。信息不对称程度与流动性负相关,所以 LR 高对应 ASY 低,这一点在构建合成指标时必须注意方向。

与 Amihud 相比,流动性比率更强调“深度”,不只看单笔交易的价格冲击,而是看市场整体吸纳资金的能力。实操中的常见做法是:以周为频率计算原始 LR,再在一个月内取简单平均作为月度变量。周频可以一定程度规避日频数据中个别极端值的干扰,同时又不至于把窗口拉太长导致指标的时效性丢失。

这里有一个必须提前处理的问题:(\Delta P) 在停牌或涨跌停日会出现精确 0 值。分母出现0,整个分数就是无穷大。常见的处理方式是给分母加一个平滑项:

[ LR_{i,t} = \frac{\sum P_{i,j} V_{i,j}}{\sum |\Delta P_{i,j}| + \epsilon} ]

实际操作中我见到更普遍的做法是直接剔除分母为 0 的交易日,而不是加 epsilon。两种做法各有取舍:加 epsilon 保留了样本量,但让流动性比率在极端行情下出现轻微低估;剔除法更干净,但在1990年代早期日频数据本来就不厚的情况下,会丢掉不少观测。如果样本量充足,优先用剔除法;如果某个月交易日数量低于某个阈值(比如15天),该月 LR 直接置为缺失。参数怎么定没有绝对标准,但至少要在输出表里加一列“月内有效交易日数”,方便后来人判断数据质量。

2.3 收益率反转:用滞后收益的系数衡量信息不对称

收益率反转指标来自市场微观结构理论中的一条经典现象:在存在做市商或流动性提供者的市场里,临时的价格冲击会在后续交易日被修复,表现为收益率负自相关。深度知情交易者少时,价格更接近随机游走;流动性冲击主导时,反转更明显。

所以学术上的操作是跑一个日度回归:

[ R_{i,t} = \alpha + \beta R_{i,t-1} + \varepsilon_{i,t} ]

(\beta) 显著为负,说明存在反转效应。反转越强,说明价格中噪音成分越大,信息不对称程度越高。注意这里和一般因子研究里说的“短期反转因子”是两码事——那个用的是过去一个月累计收益,用的是同一段时间的收益符号;而这里的反转指标是滞后一日的收益对当日收益的回归系数,是序列相关性,一个是横截面特征,一个是时间序列特征,别混用。

实际构建时,要在一个回看窗口内做滚动回归。窗口长度是核心参数。窗口拉太长,比如三年,指标平滑过头,捕捉不到信息环境的变化;窗口太短,比如一个月(约22个交易日),回归的样本量不足,估计出的 (\beta) 噪声巨大。常见做法是用过去 250 个交易日(约一年)滚动估计,要求至少 120 个有效观测,否则置为缺失。

还要考虑是否加入市场收益作为控制变量。不加的话,(\beta) 里混入了市场层面的反转效应;加的话,个股的残差反转会更纯粹,但计算量加大,而且早期数据里市场收益本身的完整性也存疑。我的做法是同时输出两个版本——不加市场收益的原始版和加市场收益的残差版,供下游使用者按需取用。

3. 用 Python 从原始行情重建 ASY 指标:最小可运行方案

3.1 数据准备与字段选型

拿到最原始的日行情数据时,字段通常有trade_date、stock_code、close、pre_close、volume、amount。注意volume是股数,amount才是成交金额,很多人在这里犯错——把股数当金额用进 Amihud 公式,出来的 ILLIQ 数量级完全不对。1990年代一些早期数据源里amount字段缺失严重,这就是为什么标题里的数据集从1991年开始整理——恰好是这两个字段相对规范可用的起点。

数据读入后第一步不是算指标,是做身份证级别的字段校验。我一般会写这段代码:

import pandas as pd import numpy as np df = pd.read_csv("daily_1991_2022.csv", parse_dates=["trade_date"]) df = df.sort_values(["stock_code", "trade_date"]).reset_index(drop=True) # 核心校验:amount 是否为正,close 与 pre_close 是否齐全 check_amount = (df["amount"] <= 0).sum() check_close = df["close"].isna().sum() print(f"异常成交额样本: {check_amount}, 缺失收盘价样本: {check_close}") # 保留必要字段,减少后续计算内存占用 df = df[["stock_code", "trade_date", "close", "pre_close", "amount"]].copy()

这里有两个参数选择值得解释。第一,parse_dates需要提前确认trade_date的格式,有些数据源给的是19910101这种整数,有些给的是1991-01-01字符串,解析前先统一。第二,为什么amount异常值只要“非正”就剔除?因为成交金额非正意味着数据源内部错误,不是合法的停牌标记。停牌日通常表现为整行记录缺失,而不是amount=0,这一点后面专门说。

预处理还有一个关键步骤:用pre_close重新计算日收益率,而不是用close直接算pct_change。原因在于除权除息日close会跳空,pct_change会把分红送股当成价格暴跌,而pre_close是经过复权调整过的前收,两者结合才能算出真实收益率:

df["ret"] = df["close"] / df["pre_close"] - 1.0 # 剔除收益率绝对值>21%的样本(涨停10%/ST5%/跌停对称,留足余量) # 1996年涨跌停制度之前没有10%限制,21%阈值只用于过滤数据源错误 df = df[(df["ret"].abs() <= 0.21) | (df["trade_date"] < "1996-12-16")] print(f"过滤后样本量: {len(df)}")

这里 21% 这个阈值的数据逻辑是:1996年12月16日起实行10%涨跌停制度,ST股是5%,考虑部分股票上市首日无限制,21% 足以识别明显的价格错误又不会误伤刚上市样本。1996年之前的样本不设限,因为当时还没有统一的涨跌停幅度。

3.2 月度截面上计算三个子指标

核心计算分两层:先算日频指标,再合成月频面板。定义好变量后写一个纯函数,用groupby跑,效率基本够。2000只股票32年约900万行数据,边算边存约一两分钟。

def compute_daily_metrics(df): df = df.copy() # 非流动性比率: |ret| / amount(单位: 百万元), *10000 调整量级 df["illiq"] = (df["ret"].abs() / (df["amount"] / 1e6)) * 10000 # 流动性比率: 周频汇总, 这里先标记ISO周 df["iso_week"] = df["trade_date"].dt.isocalendar().week.astype(int) df["iso_year"] = df["trade_date"].dt.isocalendar().year.astype(int) # 收益率反转: 用滚动窗口, 此处留待月度合成时处理 df["ret_lag1"] = df.groupby("stock_code")["ret"].shift(1) return df df = compute_daily_metrics(df)

注意iso_week和iso_year的组合才能唯一标识跨年周,比如2020年最后一周的ISO周编号是53而年份可能是2021,直接用week会把不同年份的第1周混在一起。另一处细节是除以1e6把成交金额从元换成百万元,再乘10000把 ILLIQ 调整到 1 附近的可读量级——这一步只是数值尺度变换,不影响后续回归的方向和显著性,但影响回归系数的展示精度。

月度合成时,ILLIQ 取月内简单平均;流动性比率按周先聚合再对周值取简单平均;收益率反转则要做滚动回归:

def monthly_illiq_and_lr(df): grouped = df.groupby(["stock_code", "trade_date.dt.year", "trade_date.dt.month"]) # 此处用 agg 简化, 实际可用 groupby.apply monthly_illiq = df.groupby(["stock_code", "df_year", "df_month"])["illiq"].mean() return monthly_illiq.reset_index()

流动性比率反转这里贴的是框架代码,重点想说明的是:月度合成前先做好 ISO 周标记,groupby的粒度是股票 + ISO年 + ISO周,先求每周的 LR,再用月内整数周做平均。这样不会因为某个月首尾各含半周导致数值振荡。

3.3 滚动回归估计收益率反转系数

收益率反转的滚动回归,严谨的写法要用statsmodels的RollingOLS或者手写循环。手写循环虽然丑,但能自主控制最小观测数、是否加市场收益控制变量,而且出错时排查起来更直接。

import statsmodels.api as sm def estimate_reversal(ret_series, min_obs=120): """输入单只股票按时间排序的日收益率序列, 返回滚动250日窗口的滞后项系数""" beta_list = [] idx_list = [] for i in range(250, len(ret_series)): window = ret_series.iloc[i-250:i] window = window.replace([np.inf, -np.inf], np.nan).dropna() if len(window) < min_obs: beta_list.append(np.nan) idx_list.append(ret_series.index[i]) continue x = window.shift(1).dropna() y = window.loc[x.index] if len(x) < min_obs: beta_list.append(np.nan) idx_list.append(ret_series.index[i]) continue x_const = sm.add_constant(x) model = sm.OLS(y, x_const).fit() beta_list.append(model.params.iloc[1]) idx_list.append(ret_series.index[i]) return pd.Series(beta_list, index=idx_list)

这段代码有三个参数值得讲。第一,min_obs=120是经验值——低于这个观测数,OLS 估计的系数方差太大,反转指标会变成纯噪声,放进回归里只会增加标准误。第二,窗口里先replace无穷值再dropna,是为了防停牌引起的除零错误。第三,.shift(1)在window内部做滞后,确保滞后期不会跨越窗口边界,这里的索引对齐是 pandas 隐式的,靠window.loc[x.index]锁住配对关系。

250日窗口的回看长度也可以根据用途调整。做学术研究引用文献时用250日;做量化因子测试时,我倾向于120日,因为120个交易日约等于半年,对信息环境变化更敏感,代价是系数噪声更大。到底选哪个,没有标准答案,本质上是在“灵敏度”和“稳健性”之间做权衡。输出面板数据时,最好把两个窗口同同时算出来,留给使用方自己决定。

4. 1991-2022:横跨32年数据的时间维度处理与制度断点

4.1 早期数据缺失与退市样本的幸存者偏差

做1991到2022的长面板,最大的敌人不是计算,是样本存活率。许多初做面板的人直接从某个行情源拉一份“当前上市股票”的列表,再去取历史行情,这等于天然丢掉了所有已经退市的股票。1990年代上市的股票里,相当一部分后来经营恶化、退市或者被借壳,它们的共同特征是信息不对称程度大概率高于存活者。丢掉它们,结果就是样本偏向信息披露好的大公司,信息不对称均值被系统性低估,后续任何回归都会带上偏差。

正确做法是从历史上市状态表出发,把某一天曾经上市过的所有股票代码都纳入建库,包括已退市股票。具体到代码实现:

# 假设上市状态表含 stock_code, list_date, delist_date status = pd.read_csv("list_status.csv", parse_dates=["list_date", "delist_date"]) today = pd.Timestamp("2022-12-31") # 生成所有股票在每个月的“是否已上市”状态 month_end_dates = pd.date_range("1991-01-31", "2022-12-31", freq="ME") # 注意: 旧版pandas用 freq="M", 新版用 "ME" stock_status = [] for code, row in status.iterrows(): for dt in month_end_dates: if row["list_date"] <= dt and (pd.isna(row["delist_date"]) or row["delist_date"] >= dt): stock_status.append({"stock_code": code, "month_end": dt}) stock_status = pd.DataFrame(stock_status)

这段循环看起来笨,但它的价值在于把“当前还活着”的样本库转换成“当时还活着”的月度动态样本库。凡是delist_date早于当月月末的股票,当月就不再出现在面板里。这样处理之后,退市前的最后一两年数据仍在样本中——而这部分数据恰恰是信息不对称程度急剧放大的时期,含金量最高。

另一个问题是1991到1995年间上市公司数量极少,早期每个月的截面可能只有几十只股票。这带来两个后果:一是月度截面回归的自由度极低,任何异常值都会主导结果;二是早期股票的成交量极小,amount字段缺失率高。建议处理方式是:在输出面板里增加一列n_stocks记录当月有效样本量,并在论文或报告里明确标注“1995年以前结果需谨慎解读”。这不是偷懒,是长面板研究的诚实要求。

4.2 涨跌停制度和做空机制带来的结构性断点

1996年12月16日实施10%涨跌停制度之前,日收益率可以任意大,Amihud 指标的分母(成交额)常常是零或缺失,因为市场太清淡。之后,涨跌停约束了收益率的最大波动幅度,这让 ILLIQ 的分布形态前后完全不同。技术上要做的不是强行统一口径,而是在面板里加入制度断点虚拟变量,让使用方可以自行检验断点前后系数是否稳定。

2010年融资融券试点是第二个断点。做空机制出现后,坏消息不再只能通过抛售现货来表达,反转指标的微观含义会变弱——因为融券卖出的订单流本身就是知情交易的一种表现形式,它与普通散户的情绪化抛售造成的反转在结构上完全不同。如果数据集覆盖到2010年以后,一定要单独标记样本是否属于融资融券标的:

# 融资融券标的列表格式: stock_code, start_date margin = pd.read_csv("margin_eligible.csv", parse_dates=["start_date"]) def flag_margin_period(df, margin): df = df.merge(margin[["stock_code", "start_date"]], on="stock_code", how="left") df["is_margin"] = (df["trade_date"] >= df["start_date"]).astype(int) df.loc[df["start_date"].isna(), "is_margin"] = -1 # -1表示从未进入名单 return df.drop(columns=["start_date"])

-1 / 0 / 1的分类比简单的0/1哑变量多一层信息:-1是全程不可做空,0是可做空制度实施前,1是实施后。在下游回归里,可以直接用这一列做交乘项,检验“信息不对称的定价效应在可做空股票中是否更弱”。很多实证研究不做这个区分,导致在2010年后的样本里混入了两类性质完全不同的标的。

沪深港通开通(2014年)也是一个值得关注的点,它改变了股票的投资者结构,增加了境外机构投资者的占比。机构投资者比例高,信息不对称的度量会发生系统性变化。如果你的数据集字段里有持股比例或北向资金数据,可以考虑再增加一列is_connect标识2014年11月17日之后是否为沪深港通标的。标题里的数据集不一定包含这个字段,但自己动手做扩展时有这个意识会少踩不少坑。

4.3 复权方式的选择与收益率的连续性

除权除息带来的价格跳空,是长周期数据里最隐蔽的坑。某只股票在除权日close从20元“跌”到15元,如果直接用close / pre_close - 1就会算出-25%的收益率,这个数字会被 Amihud 指标当成巨大的价格冲击,REG反转回归也会把这一天当异常反转。1990年代高送转极多,10送10屡见不鲜,不处理复权的数据在1991到2005年间基本没法用。

标准做法是使用前复权价格。前复权保持最新价格不变,历史价格按分红送股比例调整,这样收益率序列是连续的,除权日不会产生假跳空。计算时用hfq_close与hfq_pre_close取对数差分,或者直接用后复权价格取一阶差分再求收益率。更严谨的做法是用后复权价格:

# 后复权价格: 以某个早期基准日为准, 将分红送股全部累加回价格中 df["ret_adj"] = df["close_hfq"] / df["close_hfq"].shift(1) - 1.0

注意pre_close本身就是交易所发布的“前收盘参考价”,已经包含了除权除息调整,用close / pre_close - 1在大多数情况下的收益序列也是连续的。问题出在某些数据源在除权日的pre_close字段直接填了未复权的昨日收盘价,导致跳空。安全的做法是拿到行情后随机抽10个除权日(通过分红送股公告日期定位),手动对比pre_close和前一日close的关系,若出现比例明显不等于1的情况,就要考虑数据源的复权字段是否可靠。

复权基准的第二个问题是前复权价格会随最新行情变化而变化。如果某数据源的复权基准是动态的,那么2000年截面的历史价格会随着2022年的分红事件不断被改写。对学术研究来说,用最新一次下载的数据计算历史指标没问题;但如果你打算隔几年更新一次面板,前后两次计算的同一只股票2000年收益率可能有细微差异。建议在输出元数据里写清楚复权基准日期,否则后续更新数据时会出现“同一指标前后不一致”的信任危机。

5. ASY 指标计算避坑指南:从数据源到回归口径的五条踩坑记录

5.1 停牌日混入样本,反转系数出现极端异常值

现象:某只股票某个月的反转系数达到-8.7,而同行业其他股票普遍在0到-0.5之间。单独看日收益率序列,发现停牌复牌当天收益率巨幅波动,停牌前一日收益被纳入了滞后项,复牌日收益被纳入了当前项,两者一除,回归系数被拽到离谱的位置。

原因:停牌不是缺失值,而是行情池里没有那一行记录。这导致复牌日的ret_lag1取到的是停牌前最后一天的收益率,而停牌期间信息累积到了复牌日集中释放,形成虚假的“隔夜反转”。

解决:在计算滞后项前,先检查每个交易日的上一交易日是否连续。如果trade_date间隔超过4个自然日,认定存在停牌,将滞后项置为缺失,不参与回归。

df["date_diff"] = df.groupby("stock_code")["trade_date"].diff().dt.days df["is_suspend_gap"] = df["date_diff"] > 4 df.loc[df["is_suspend_gap"], "ret_lag1"] = np.nan

间隔阈值选4个自然日,因为正常周末间隔是2天、长假最多3到4天,超过4天基本可以确定是停牌或数据缺失。别用1天做阈值,那样周五和周一之间的正常间隔也会被误判为停牌。

5.2 涨跌停日成交极低,ILLIQ虚高

现象:某股票涨停日成交额仅为平时的五分之一,当日 ILLIQ 飙升到平时的10倍以上。把这个月平均下来,整个月的 ILLIQ 被涨停日一只独秀地抬高。

原因:涨停时买盘巨大但卖盘稀缺,成交额萎缩,而收益率固定在+10%,分子不变、分母变小,ILLIQ 天然虚高。这不是信息不对称的真实反映,而是涨跌停制度制造的伪信号。

解决:识别涨跌停日并单独标记。计算涨跌停状态用“当日收盘价是否达到涨跌停价”而不是单纯用收益率绝对值判断——1996年后主板10%、ST为5%,两个阈值不同,按股票所属板块区分。处理策略是在合成月频指标时,将涨跌停日的 ILLIQ 排除在月度平均之外,同时保留一个“月内涨跌停天数占比”字段,让下游知道该月指标是在何种市场状态下计算的。

5.3 数据源复权基准不统一,相邻年份指标断档

现象:某股票1999年从20元变成40元(10送10),同一数据源在不同批次下载的口径下,这只股票1999年全年的收益率序列完全对不上,导致前后两次算出的 ASY 指标相差30%以上。

原因:一批下载用的是向前复权,另一批用的是向后复权,或者复权基准日不同。当跨多个年份做数据更新时,复权因子被重新计算,历史价格整体平移。

解决:固定数据源和复权基准。在数据版本管理里写入复权基准日期(adj_base_date)和复权算法(fw_adj / bw_adj),每次更新数据前先检查这两个字段是否变化。如果变了,则全量重算所有历史指标,不搞增量追加。这个坑属于“不炸则已,一炸全盘皆输”的类型。

5.4 回看窗口长度不同,反转系数月度间跳动剧烈

现象:同一只股票,用180日窗口算出的反转系数为-0.2,用250日窗口算出-0.4,两者差异远大于标准误。进一步看,200日窗口时数值无规律跳动。

原因:窗口变短时,单月极端收益率在窗口内的权重变大;窗口变长时,跨度内的市场结构(如牛熊市切换)本身发生了变化。线性回归假设窗口内参数恒定,这个假设在波动大的A股市场里强得过头。

解决:不要试图找一个“最优窗口”,而是同时输出两个窗口(如120日和250日)的结果。下游用哪个取决于场景:做低频资产配置看长期指标用250日;做交易型因子用120日。数据集里同时保留两个版本,比二选一更实用。

5.5 年报数据滞后,包含未来信息的“未来函数”坑

现象:面板里有因子在2001年3月使用了股票2000年度的“审计意见”或“信息披露评级”字段,但在实际投研回测时,这些信息到2001年4月底才真正公开。回测表现很好,实盘完全失效。

原因:财务数据的披露时点远晚于会计年度结束日。年报截止日是4月30日,有些公司拖到4月底才发布。直接按会计年度合并原始数据会引入“未来函数”,尤其在回归模型里放财务变量做控制时。

解决:对每一期面板数据,生成一个info_avail_date字段,记录该条信息实际可被投资者获取的日期。对于年报字段,info_avail_date= 实际披露日,而不是12月31日。使用时要求在info_avail_date不晚于当前回测时间戳。这个处理在很多现成数据包里并不存在,拿到数据后务必自己补一层。

6. 拿到指标之后:先做这四步有效性验证再入库

6.1 分组检验:高ASY组该有更大的买卖价差

拿到计算好的ASY指标,第一件事不是直接入回归,而是验证它是否具有经济学含义。最便捷的方法是分组检验:把全市场按ASY从低到高排序分成五组(或十组),观察每组对应的平均买卖价差、换手率、分析师覆盖人数。预期结果是:高ASY组的买卖价差更大(交易成本更高)、换手率更低(交易意愿弱)、分析师覆盖更少(信息环境贫瘠)。如果这个关系不存在或不显著,说明指标构建过程有错误,不必急着进入下一步。

# 假设面板数据: stock_code, month_end, asy, spread, turnover df["asy_rank"] = df.groupby("month_end")["asy"].apply( lambda x: pd.qcut(x, 5, labels=False, duplicates="drop") ) group_summary = df.groupby(["month_end", "asy_rank"])[["spread", "turnover"]].mean()

duplicates="drop"参数必须加,因为早期月份股票数量少,分位数可能出现并列。分组检验通过后,再进入到回归阶段。

6.2 横截面回归与时间序列验证

第二个验证是检验“ASY与未来收益的关系”。信息不对称程度高的公司,预期收益应当更高(因为投资者要求信息风险补偿),但这在学术上本身是有争议的,可能为正也可能为负。更稳妥的验证方式是检验ASY与已知的直接信息不对称度量(如买卖价差)的相关性,而不是与收益的关系。收益的影响因素太杂,用收益来验证微观结构指标容易被其他因子干扰。

从操作层面看,先做同期相关性矩阵,检验ASY与换手率、市值取对数、波动率的相关系数方向和符号是否符合理论预期。成交额小的股票波动率高、ASY通常也高;大市值股票的ASY普遍低。如果这个结构都不成立,说明计算环节有问题。

最后再从使用角度提一个建议:这份32年面板数据,尽量不要只输出一个ASY_Total合成指标,把三个子指标(非流动性比率、流动性比率、收益率反转)全部保留。很多场景下,收益率反转和 Amihud 捕捉的信息维度不同,前者更偏交易行为,后者更偏流动性与订单流特征,合成综合指标等于把信息压缩了,但下游研究者可能恰恰需要其中的某一个维度。保留原始子指标还有一个好处——做稳健性检验时,可以分别替换子指标看结论是否变化。这是我在做类似面板数据时的一个习惯:宁可多给几个原始口径,也不要把合成变成黑匣子。

32年的面板数据,最难的不是代码,是口径一致性。下载现成的网盘数据能省掉计算时间,但计算过程的知识依然需要理解,因为这类数据集通常不会告诉你每个指标是用哪个窗口、哪种复权方式、哪套制度断点处理规则算出来的。如果某天你拿着这份数据做出来的结论跟别人不一致,问题大概率不在这份数据本身,而在计算结果背后被省略的那些参数选择里。希望这些排查思路能帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 11:32:57

Python + JSON Schema 实现工单结构化输出与本地复核

客服系统最危险的自动化&#xff0c;不是模型答错一句话&#xff0c;而是把“退款 9999 元”当成真指令一路执行。结构化输出&#xff08;Structured Outputs&#xff09;能要求模型按 JSON Schema 返回字段&#xff1b;但它不是业务真相。你还需要第二道本地门&#xff1a;金额…

作者头像 李华
网站建设 2026/10/16 10:12:12

声发射信号离散程度分析:用MATLAB滑窗计算变异系数CV的工程实践

手里有一批声发射检测数据&#xff0c;需要快速评估材料在不同加载阶段信号的离散程度&#xff0c;我第一个想到的就是算变异系数CV值。声发射&#xff08;Acoustic Emission&#xff0c;AE&#xff09;信号的振铃计数、幅值、能量这些参数&#xff0c;单看均值只能反映“平均水…

作者头像 李华
网站建设 2026/10/17 4:18:47

BrewUI 装不上?先别重装系统,90% 的报错都藏在这 5 个地方

BrewUI 装不上&#xff1f;先别重装系统&#xff0c;90% 的报错都藏在这 5 个地方 【免费下载链接】BrewUI &#x1f4fa; Homebrews official macOS GUI 项目地址: https://gitcode.com/GitHub_Trending/br/BrewUI BrewUI 是 Homebrew 官方的 macOS 原生图形界面&#…

作者头像 李华
网站建设 2026/10/16 15:41:31

Kubernetes内存驱逐工具:智能检测与Pod驱逐实战

1. 项目缘起&#xff1a;为什么需要一套内存驱逐工具干过K8s生产运维的兄弟应该都有这种经历&#xff1a;半夜被告警电话叫醒&#xff0c;打开监控一看&#xff0c;某个节点Memory Pressure持续亮红&#xff0c;Pod各种EvictionFailed、OOMKilled&#xff0c;业务方在群里疯狂刷…

作者头像 李华
网站建设 2026/10/16 6:08:10

编译原理NFA转DFA实现:Python子集构造法详解与避坑指南

简介&#xff1a;这份资源面向学习编译原理、需要动手实践词法分析环节的高校学生与自学者&#xff0c;聚焦非确定有限自动机&#xff08;NFA&#xff09;到确定有限自动机&#xff08;DFA&#xff09;的转换这一编译器设计关键步骤。压缩包共3个文件&#xff0c;以py脚本、txt…

作者头像 李华
网站建设 2026/10/16 7:41:44

SpringBoot小区健身房管理系统毕设:源码、论文与部署全解析

每年这个时候&#xff0c;后台咨询里最多的就是“SpringBoot毕设怎么做”。尤其是那种“功能不能太简单、页面上要拿得出手、最好能把论文一起带出来”的需求&#xff0c;几乎都指向同一条路线。今天我想认真聊一聊“基于SpringBoot的小区健身房管理系统”这个项目&#xff0c;…

作者头像 李华