财务质量因子研究:识破财务数据的“漂亮“陷阱
摘要
本篇文章中,我们将基于申万宏源证券分析师曹春晓、文雨的报告《财务造假启示录:财务质量因子研究》对财务造假的分析研究来进行策略复现。
识破财务数据的“漂亮陷阱”
根据《财务造假启示录:财务质量因子研究》一文梳理的财务造假逻辑(见下图):
财务造假常见手段及其财务特征
我们构建如下财务质量因子:
由于不同行业间经营差异明显,比如房地产行业高预收、高存货,医药行业 高毛利等,我们将各项财务指标统一计算为行业内所处百分位数,再进行因子检验。
另外,利润表和现金流量表科目使用单季度指标值计算。
*TTM介绍:TTM数据是一个滚动概念,每个季度都会不同。虽然它的起始点会发生变化,但却始终包括有四个不同的季度(1、2、3、4; 2、3、4、1; 3、4、1、2; 4、1、2、3),虽然这四个季度有可能属于两个不同的自然年度,但仍然弥补了上市公司季节性的客观差异所造成的影响。这样一来,相隔两个季度之间的TTM 数据比较时,其采样中总会出现3 个季度的重合,1 个季度不同。正是由于加入了3 个重合的季度,则使这种比较在一定程度上过滤掉小波动,进而更加客观地反映上市公司的真实情况。
*同比增长率介绍:同比即与上一年同期的数量作比较,同比增长率=(本期数-上一年同期数)/ 同期数 * 100%。
01
数据获取
剔除ST和当日不能交易的股票
def del_st(univ, date):
st_df = rqdatac.is_st_stock(univ, start_date=date, end_date=date)
remove_st_univ = st_df[st_df == False].columns.tolist()
return remove_st_univ
def del_suspended(univ, date):
suspended_df = rqdatac.is_suspended(univ, start_date=date, end_date=date)
remove_susp_univ = suspended_df[suspended_df == False].columns.tolist()
return remove_susp_univ
def del_new(univ, date, day = 60):
remove_new_univ = []
for stk in univ:
listDate = rqdatac.instruments(stk).days_from_listed(date)
if listDate > day:
remove_new_univ.append(stk)
return remove_new_univ
02
数据处理
由于不同行业间经营差异明显,比如房地产行业高预收、高存货,医药行业 高毛利等,我们将各项财务指标统一计算为行业内所处百分位数。
def fac_pct_process(factor_name, data):
data_pct = pd.DataFrame()
for ind_name in data['industry'].unique():
temp_data = data[data['industry'] == ind_name].copy()
temp_data[factor_name] = temp_data[factor_name].rank() / len(temp_data[factor_name])
data_pct = data_pct.append(temp_data)
data_pct.reset_index(drop=True ,inplace=True)
return data_pct
03
因子分析
(剔除 金融服务,银行,非银金融)的股票
金融行业的运营模式独特,股票价格和其他行业指数相关性低,通过全市场测试选出的 alpha 因子可能在金融行业内并不适用。
另外金融行业和其它行业在会计计量有所不同,例如资金借贷和证券买卖在一般生产性企业中属于金融活动,但它们却是这两个行业的主营业务;而且这两个行业没有毛利润(银行可以用利差收入替代)、流动资产和流动负债等会计项目,无法计算 GPM、GPOA 和 ROIC 指标。为保证统一,我们在测试选股因子表现时,都把金融行业的股票剔除。
单因子分析
分析的股票池为剔除60天新股、停牌股、st股、金融服务、银行和非银金融后的全A股。
def group_ret(fac, forward_return, n_quantile=10, hedging=True):
cols_mean = [i+1 for i in range(n_quantile)]
cols = cols_mean
common_index = fac.index.intersection(forward_return.index)
excess_returns_means = pd.DataFrame(index=common_index, columns=cols)
for dt in excess_returns_means.index:
qt_mean_results = []
tmp_factor = fac.loc[dt].dropna()
tmp_return = forward_return.loc[dt].dropna()
tmp_return = tmp_return.loc[tmp_factor.index]
tmp_return_mean = tmp_return.mean()
pct_quantiles = 1.0 / n_quantile
for i in range(n_quantile):
down = tmp_factor.quantile(pct_quantiles*i)
up = tmp_factor.quantile(pct_quantiles*(i+1))
i_quantile_index = tmp_factor[(tmp_factor<=up) & (tmp_factor>=down)].index
if hedging == True:
mean_tmp = tmp_return[i_quantile_index].mean() - tmp_return_mean
elif hedging == False:
mean_tmp = tmp_return[i_quantile_index].mean()
qt_mean_results.append(mean_tmp)
excess_returns_means.loc[dt] = qt_mean_results
return excess_returns_means
存货周转率、应收账款周转率单调性不明显
存货周转率,是衡量和评价企业购入存货、投入生产、销售收回等各环节管理状况的综合性指标。存货周转速度越快,存货的占用水平越低,流动性越强,存货转换为 现金、应收账款的速度越快,企业的营运能力越强。
应收账款周转率,指的是企业在一定时期内赊销净收入与平均应收账款余额之比,衡量企业应收账款周转速度及管理效率。
存货周转率和应收账款周转率都是财务质量需重点关注的指标,不过从指标分组来看,存货周转率、应收账款周转率均不具备较好的单调性。
plt.rc("font",family="Arial Unicode MS", size="12")
group_return_10 = group_ret(IT, forward_return, n_quantile=10, hedging=True)
group_ret_plot(group_return_10, '存货周转率十分组表现')
group_return_10 = group_ret(ART, forward_return, n_quantile=10, hedging=True)
group_ret_plot(group_return_10, '应收账款周转率十分组表现')
应收账款周转率同比改善指标效果更好
虽然应收账款周转率指标本身不具备良好的区分能力,但其同比改善指标的选股能力较好,十分组单调性均较为理想。
group_return_10 = group_ret(ART_yoy, forward_return, n_quantile=10, hedging=True)
group_ret_plot(group_return_10, '应收账款周转率同比改善指标的十分组表现')
总资产净利率单调性不明显
总资产净利率反映的是公司运用全部资产所获得利润的水平,即公司每占用1元的资产平均能获得多少元的利润。该指标越高,表明公司投入产出水平越高,资产运营越有效,成本费用的控制水平越高。体现出企业管理水平的高低。
从指标分组来看,总资产净利率不具备较好的单调性。
group_return_10 = group_ret(ROA, forward_return, n_quantile=10, hedging=True)
group_ret_plot(group_return_10, '总资产净利率因子十分组表现')
对财务质量因子进行批量分析
分析指标介绍:
IC:秩相关系数,衡量因子与未来收益的相关度,是指在某个时点上,给定股票池,股票池中所有股票的因子暴露值排名与其下期回报排名的截面相关系数
IC_IR:IC / IC的标准差,衡量因子IC的稳定性
p-value:衡量因子与未来收益相关度的显著性,通常我们认为 p-value 低于0.05 的因子对未来收益有预测性
正显著率:衡量因子的IC大于0时,ic在时间序列上的显著比例(p-value 低于0.05)
负显著率:衡量因子的IC小于0时,ic在时间序列上的显著比例(p-value 低于0.05)
多空组合年化收益率:按因子值对股票进行排序,构建出10组股票组合,以多头组合(第一组)减去空头组合(最后一组),得出的月度多空收益,以此计算出多空组合的年化收益率
多空组合年化波动率:按因子值对股票进行排序,构建出10组股票组合,以多头组合(第一组)减去空头组合(最后一组),得出的月度多空收益,以此计算出多空组合的年化波动率
多空组合夏普比率:衡量多空组合相对于无风险组合的表现,是多空组合所获得风险溢价的度量——即如果多空组合额外承担一单位的风险,可以获得多少单位的收益作为补偿。计算方式:多空收益相对无风险收益的超额收益率均值 / 多空组合相对无风险收益的超额收益率的波动率
多空组合最大回撤:多空组合走到最低点时收益率回撤幅度的最大值,最大回撤是评估多空组合极端风险的重要指标
财务质量因子测试结果
在所构建的财务质量因子中,应收账款周转率(同比增长率)、所得税费用/营业收入(同比增长率)、流动负债/负债合计、总资产周转率等因子表现较好。
因子之间的相关性分析
分析的财务质量因子有:应收账款周转率(同比增长率)、所得税费用/营业收入(同比增长率)、流动负债/负债合计、总资产周转率,流动负债/负债合计 和 总资产周转率 有相关性(0.26),其他的因子相互之间的相关性都不高。
财务质量因子之间及与其他常见因子之间的相关性分析
总资产周转率 与盈利因子的相关性较高(0.42)
其他财务质量因子 与其他常见因子(市值、估值、盈利等)之间的相关性不高
04
财务质量因子合成
从因子测试结果来看,部分财务质量指标不具备较好的单调性,我们筛选区分能力较好的因子进行合成,构建财务质量因子。
合成因子包含:应收账款周转率(同比增长率)、所得税费用/营业收入(同比增长率)、流动负债/负债合计、总资产周转率。
合成后的财务质量因子在样本空间下的区分能力和分组单调性明显增强:
fac_cum = (ART_yoy + IT_OPR + CTT + TAT) / 4
fac_cum = fac_cum.dropna(how='all', axis=0)
group_return_10 = group_ret(fac_cum, forward_return, n_quantile=10, hedging=True)
group_ret_plot(group_return_10, '财务质量因子分组单调性有明显提升')
group_return_5 = group_ret(fac_cum, forward_return, n_quantile=5, hedging=True)
group_return_5.index = pd.to_datetime(group_return_5.index)
(group_return_5 + 1).cumprod().plot(figsize=(12,5), grid=True, title='财务质量因子分组对冲净值曲线')
合成的财务质量因子,在全市场非金融股票中,因子IC均值为1.95%,IC_IR为0.44
factor_report({'财务质量因子':fac_cum}, forward_return, -1, 'monthly')
十分组间单调性较为理想,多空组合表现稳定,最大回撤6.46%
多头(第十组)年化收益率约为18.88%,夏普比率0.72
group_return_10 = group_return_10.rename(columns={1:'空头组合',10:'多头组合'})
group_return_10.index = pd.to_datetime(group_return_10.index)
(group_return_10[['多头组合','空头组合','多空组合']] + 1).cumprod().plot(
figsize=(12,5), grid=True, title='财务质量因子多空组合净值曲线', color=['#00BFFF','grey','tomato'])
Alpha 来源自市场的失效,市场信息未得到充分利用,虽然无法像资产定价理论中那样假设所有投资者都是理性投资人,但是理性投资个体的存在会使得市场趋于有效,alpha 信息的有效性会减弱,这种现象称之为 alpha 衰减。
因子IC的衰减分析
Alpha 因子的效用并非在未来n个月均匀分布,而是呈现逐步衰减的形态,也就是说我们从月初获得的 alpha 要比n个月后获得的 alpha 高,持仓n个月不动的调仓方式在后半段资金利用效率较低,有必要在 alpha 衰退之前调仓。
另一方面,高的换手率在实际交易中会受交易成本影响很大,从而导致实际能获得的 alpha 大打折扣。
因子在时间序列上的IC和 IC的衰减分析
IC:秩相关系数
the number of IC(all, plus, minus):plus代表IC为正的数目,minus代表IC为负的数目
IC的衰减分析:我们希望IC的衰减速度更慢,这样可以降低因子的换手率
财务质量因子在119个月份中,ic为正的月份有76个;IC的衰减速度较慢,财务质量因子在3个月后,仅损失了四分之一的IC。
ic_data = rank_IC(fac_cum, forward_return)
IC_plot(ic_data)
IC_decay_plot(fac_cum, chgpct_a)
与传统大类因子的相关性
从与盈利,估值,成长,市值等因子的相关性来看,财务质量因子与成长、盈利、估值因子间存在一定的相关性,说明成长、盈利、估值可以用来解释财务质量因子的alpha来源。
cor = 0
for date in ART.index:
tmp = pd.concat([fac_cum.loc[date, :].to_frame('财务质量因子'),ROE.loc[date, :].to_frame('盈利'), EP.loc[date, :].to_frame('估值'), INP.loc[date, :].to_frame('成长'), MKT.loc[date, :].to_frame('市值')], axis=1)
cor = tmp.corr() + cor
corr_df = (cor / len(ART)).iloc[[0],1:]
corr_df.squeeze().plot(kind='bar', figsize=(5,4), grid=True, title='与盈利,估值,成长存在一定相关性')
corr_df
财务质量因子的行业分布
从下图可以看到,不同行业间的因子均值差别较小。另我们剔除了金融行业,所以没有金融行业的数据。
IND_median = IND_df.groupby('industry').median()
plt.rc("font",family="Arial Unicode MS",size="12")
IND_median.plot(kind='bar', figsize=(13, 4), grid=True)
05
财务质量因子的中性化处理
为了进一步验证财务质量因子的选股能力,我们通过横截面回归取残差的方式对误差因子进行中性化处理。首先,我们剔除市值与行业的影响:
其中𝐹𝐸𝑖为原始财务质量因子,𝐿𝑛(𝑐𝑚𝑣) 为流通市值对数值,Ind为行业哑变量,行业划分采用申万一级行业
下一步,我们不仅剔除市值与行业的影响,同时也剔除盈利、估值和成长因子的影响:
其中𝐹𝐸𝑖为原始财务质量因子,𝐿𝑛(𝑐𝑚𝑣) 为流通市值对数值,ROE、EP、NPG分别为盈利、估值和成长因子,Ind为行业哑变量,行业划分采用申万一级行业
最后,我们对比原始财务质量因子、中性化市值与行业后的财务质量因子 和 中性化市值、行业、盈利、估值和成长因子后的财务质量因子:
中性化市值与行业后的财务质量因子,相对原始财务质量因子,多空净值有所提高(因子分组能力提高)。
而中性化市值、行业、盈利、估值和成长因子后的财务质量因子,可能是剔除了太多的信息,因子分组能力明显下降。
long_short_df.index = pd.to_datetime(long_short_df.index)
(long_short_df + 1).cumprod().plot(
figsize=(12,5), grid=True, title='财务质量因子多空组合净值曲线')
简单来说
我们分析了财务造假常见手段和对应的财务特征,构建了存货周转率、 营业成本率ttm、流动负债 / 负债合计、递延所得税负债、应收账款周转率(同比增长率)等财务质量因子,因子值为相关财务指标所处行业内百分位数。
同比类指标比原先财务指标有更好的选股效果。
应收账款周转率(同比增长率)的ic最高。
表现较好的财务质量因子之间的相关性,及与其他常见因子之间的相关性均较低。
以应收账款周转率(同比增长率)、所得税费用/营业收入(同比增长率)、流动负债/负债合计、总资产周转率等因子构建合成的财务质量因子,与成长、盈利、估值因子存在一定的相关性。
合成的财务质量因子在剔除市值、行业之后,因子分组能力得到提高;而剔除市值、行业、盈利、估值和成长因子后,因子分组能力下降。
欢迎点击阅读原文查看研究全部内容!
题图 by Clem Onojeghuo on Unsplash
Happy Coding
米筐量化研究平台
交流|学习|改变
长按扫码关注我们