上市公司真实盈余管理计算代码及数据 结果说明原始数据为A股上市公司2000-2022的数据由于指标计算需要用到前两年的数据因此最终回归结果为2002-2022真实盈余管理数据 包含原始数据代码及计算结果说到A股上市公司的盈余管理很多人第一反应都是调应计项目的那些花活比如提前确认收入、减值计提乱搞之类的但其实真实盈余管理才是更难查的——毕竟人家是真的调了交易不是光改报表数字。最近帮实验室的师弟跑了2000-2022年的A股真实盈余管理数据顺便把完整的流程、代码和踩过的坑都整理出来了省得大家又去翻那些半吊子的外文翻译教程。先唠唠核心逻辑主流的真实盈余管理REM计算用的是Roychowdhury的经典模型核心是算三个异常指标异常经营现金流卖东西收到的钱和报表里的现金流差多少异常生产成本囤货、扩产的真实成本和正常水平差多少异常酌量性费用乱砍销售/管理费用凑利润最后把三个指标合成一个综合得分数值越大说明盈余管理程度越高。而且因为要用到前两年的财务数据最终能用的样本是2002-2022年的刚好符合要求。先搞数据准备我用的是CSMAR的基础财务表大家如果有免费数据源比如Tushare也可以凑需要的变量无非就是股票代码、年份、总资产、营业收入、经营现金流、存货、销售/管理费用、营业成本这些。如果是自己合并原始数据的话记得按股票代码年份做主键关联别把不同公司的年份混在一起血的教训上代码直接抄就能跑我平时都是用Python跑的代码写得很随性改改变量名就能用import pandas as pd import numpy as np import statsmodels.formula.api as smf df pd.read_csv(a_stock_fin_raw.csv, dtype{stkcd: str}) # ---------------------- 基础数据清洗 ---------------------- # 剔除金融行业证监会行业代码J、ST/*ST股还有异常值 df df[df[indcd] ! J] df df[~df[st_status].isin([ST, *ST])] df df[df[total_asset] 0] df df[df[total_revenue] 0] # 按股票代码和年份排序方便生成滞后变量 df df.sort_values([stkcd, year]) # 生成需要的滞后项和变动额别漏了groupby不然会串公司数据 df[at_lag1] df.groupby(stkcd)[total_asset].shift(1) df[sale_lag1] df.groupby(stkcd)[total_revenue].shift(1) df[delta_sale] df[total_revenue] - df[sale_lag1] df[delta_sale_lag1] df.groupby(stkcd)[delta_sale].shift(1) # ---------------------- 计算原始的三个核心指标 ---------------------- # 1. 经营活动现金流直接拿CSMAR里的经营现金流净额就行 df[cfo] df[oper_cash_flow] # 2. 生产成本 营业成本 当期存货增加额 df[inv] df[inventory_net] df[inv_lag1] df.groupby(stkcd)[inventory_net].shift(1) df[prod] df[cost_goods_sold] (df[inv] - df[inv_lag1]) # 3. 酌量性费用 销售费用 管理费用 df[disx] df[sell_expense] df[manage_expense] # 删掉缺失滞后项的样本不然回归会报错 df df.dropna(subset[at_lag1, sale_lag1, delta_sale, delta_sale_lag1]) # ---------------------- 跑回归算异常值 ---------------------- # 1. 异常经营现金流残差就是异常值回归式按Roychowdhury的来 model_cfo smf.ols( I(cfo/at_lag1) ~ I(1/at_lag1) I(total_revenue/at_lag1) I(delta_sale/at_lag1), datadf ).fit() df[abnormal_cfo] model_cfo.resid # 2. 异常生产成本 model_prod smf.ols( I(prod/at_lag1) ~ I(1/at_lag1) I(total_revenue/at_lag1) I(delta_sale/at_lag1) I(delta_sale_lag1/at_lag1), datadf ).fit() df[abnormal_prod] model_prod.resid # 3. 异常酌量性费用 model_disx smf.ols( I(disx/at_lag1) ~ I(1/at_lag1) I(sale_lag1/at_lag1), datadf ).fit() df[abnormal_disx] model_disx.resid # ---------------------- 合成最终的真实盈余管理指标 ---------------------- df[rem] df[abnormal_prod] - df[abnormal_cfo] - df[abnormal_disx] # 保存结果记得用utf8-sig不然Excel打开会乱码 df.to_csv(a_stock_rem_2002_2022.csv, indexFalse, encodingutf-8-sig)踩过的坑提醒千万别忘记按股票代码分组做滞后变量我第一次跑的时候没加groupby把全市场的现金流直接减了结果残差全错debug了俩小时变量名一定要对应自己的数据比如如果你的经营现金流叫opcf而不是opercash_flow记得改代码里的对应位置线性回归的残差均值天然是0所以三个异常指标的均值都是0最终的rem均值也会接近0要是结果不对先看看是不是清洗步骤出问题了最后说下结果跑出来的样本就是2002-2022年的A股非金融非ST公司我大概看了下2022年的top10高REM公司都是当年有大额渠道压货、乱砍费用的典型和公告里的信息对应得上没什么问题。上市公司真实盈余管理计算代码及数据 结果说明原始数据为A股上市公司2000-2022的数据由于指标计算需要用到前两年的数据因此最终回归结果为2002-2022真实盈余管理数据 包含原始数据代码及计算结果如果不想自己跑的话也有现成的实证包比如empirical可以直接调用但自己跑一遍能搞清楚每个步骤的逻辑不会用错变量。有啥问题直接评论区问就行看到都会回~
读取提前合并好的原始A股财务数据,记得把stkcd读成字符串,不然6位代码会丢前导0
上市公司真实盈余管理计算代码及数据 结果说明原始数据为A股上市公司2000-2022的数据由于指标计算需要用到前两年的数据因此最终回归结果为2002-2022真实盈余管理数据 包含原始数据代码及计算结果说到A股上市公司的盈余管理很多人第一反应都是调应计项目的那些花活比如提前确认收入、减值计提乱搞之类的但其实真实盈余管理才是更难查的——毕竟人家是真的调了交易不是光改报表数字。最近帮实验室的师弟跑了2000-2022年的A股真实盈余管理数据顺便把完整的流程、代码和踩过的坑都整理出来了省得大家又去翻那些半吊子的外文翻译教程。先唠唠核心逻辑主流的真实盈余管理REM计算用的是Roychowdhury的经典模型核心是算三个异常指标异常经营现金流卖东西收到的钱和报表里的现金流差多少异常生产成本囤货、扩产的真实成本和正常水平差多少异常酌量性费用乱砍销售/管理费用凑利润最后把三个指标合成一个综合得分数值越大说明盈余管理程度越高。而且因为要用到前两年的财务数据最终能用的样本是2002-2022年的刚好符合要求。先搞数据准备我用的是CSMAR的基础财务表大家如果有免费数据源比如Tushare也可以凑需要的变量无非就是股票代码、年份、总资产、营业收入、经营现金流、存货、销售/管理费用、营业成本这些。如果是自己合并原始数据的话记得按股票代码年份做主键关联别把不同公司的年份混在一起血的教训上代码直接抄就能跑我平时都是用Python跑的代码写得很随性改改变量名就能用import pandas as pd import numpy as np import statsmodels.formula.api as smf df pd.read_csv(a_stock_fin_raw.csv, dtype{stkcd: str}) # ---------------------- 基础数据清洗 ---------------------- # 剔除金融行业证监会行业代码J、ST/*ST股还有异常值 df df[df[indcd] ! J] df df[~df[st_status].isin([ST, *ST])] df df[df[total_asset] 0] df df[df[total_revenue] 0] # 按股票代码和年份排序方便生成滞后变量 df df.sort_values([stkcd, year]) # 生成需要的滞后项和变动额别漏了groupby不然会串公司数据 df[at_lag1] df.groupby(stkcd)[total_asset].shift(1) df[sale_lag1] df.groupby(stkcd)[total_revenue].shift(1) df[delta_sale] df[total_revenue] - df[sale_lag1] df[delta_sale_lag1] df.groupby(stkcd)[delta_sale].shift(1) # ---------------------- 计算原始的三个核心指标 ---------------------- # 1. 经营活动现金流直接拿CSMAR里的经营现金流净额就行 df[cfo] df[oper_cash_flow] # 2. 生产成本 营业成本 当期存货增加额 df[inv] df[inventory_net] df[inv_lag1] df.groupby(stkcd)[inventory_net].shift(1) df[prod] df[cost_goods_sold] (df[inv] - df[inv_lag1]) # 3. 酌量性费用 销售费用 管理费用 df[disx] df[sell_expense] df[manage_expense] # 删掉缺失滞后项的样本不然回归会报错 df df.dropna(subset[at_lag1, sale_lag1, delta_sale, delta_sale_lag1]) # ---------------------- 跑回归算异常值 ---------------------- # 1. 异常经营现金流残差就是异常值回归式按Roychowdhury的来 model_cfo smf.ols( I(cfo/at_lag1) ~ I(1/at_lag1) I(total_revenue/at_lag1) I(delta_sale/at_lag1), datadf ).fit() df[abnormal_cfo] model_cfo.resid # 2. 异常生产成本 model_prod smf.ols( I(prod/at_lag1) ~ I(1/at_lag1) I(total_revenue/at_lag1) I(delta_sale/at_lag1) I(delta_sale_lag1/at_lag1), datadf ).fit() df[abnormal_prod] model_prod.resid # 3. 异常酌量性费用 model_disx smf.ols( I(disx/at_lag1) ~ I(1/at_lag1) I(sale_lag1/at_lag1), datadf ).fit() df[abnormal_disx] model_disx.resid # ---------------------- 合成最终的真实盈余管理指标 ---------------------- df[rem] df[abnormal_prod] - df[abnormal_cfo] - df[abnormal_disx] # 保存结果记得用utf8-sig不然Excel打开会乱码 df.to_csv(a_stock_rem_2002_2022.csv, indexFalse, encodingutf-8-sig)踩过的坑提醒千万别忘记按股票代码分组做滞后变量我第一次跑的时候没加groupby把全市场的现金流直接减了结果残差全错debug了俩小时变量名一定要对应自己的数据比如如果你的经营现金流叫opcf而不是opercash_flow记得改代码里的对应位置线性回归的残差均值天然是0所以三个异常指标的均值都是0最终的rem均值也会接近0要是结果不对先看看是不是清洗步骤出问题了最后说下结果跑出来的样本就是2002-2022年的A股非金融非ST公司我大概看了下2022年的top10高REM公司都是当年有大额渠道压货、乱砍费用的典型和公告里的信息对应得上没什么问题。上市公司真实盈余管理计算代码及数据 结果说明原始数据为A股上市公司2000-2022的数据由于指标计算需要用到前两年的数据因此最终回归结果为2002-2022真实盈余管理数据 包含原始数据代码及计算结果如果不想自己跑的话也有现成的实证包比如empirical可以直接调用但自己跑一遍能搞清楚每个步骤的逻辑不会用错变量。有啥问题直接评论区问就行看到都会回~