本文,笔者要复现的研报仍旧是老外的论文,它叫做QMJ因子。在Betting Against Beta,一个能解释巴菲特公开投资组合收益来源的因子,在大A会有怎么样的表现?这篇文章中,笔者解释了复现这个因子的原因。
计算公式和代码
这个因子的计算不复杂,但是很繁琐。
因为这个因子和Barra CNE6模型中的因子有点类似,它一共由22个因子一层一层合成,最终得到了QMJ因子。
值得一提的是,这篇论文似乎有两个版本,一个是2013年的,另外一个则是2017年的。在这里,笔者将用思维导图简单展示一下这两个版本的QMJ因子,但是复现的时候将以2017版本为主。
1
计算公式
先来看一看2013版本的因子计算公式。

再来看一看2017版本的。

看起来很复杂,但是计算起来却并不是很复杂。
因为,大部分都是两个财务指标相除,用了ReportDataLoader之后,其实都很容易计算。
这些因子中除了z-score和o-score这两个,其他的由下级合成上级的时候都需要先进行截面标准化然后求和。
不知道各位大佬有没有感受到老外的基本面因子的复杂度,就像国内的研究员狂卷量价因子一样。那么,这个因子和净虹吸效应,拥有8个计算步骤的超复杂因子,能想出来绝对是天才!,哪个更复杂呢?
2
代码
这里,笔者将分成三部分代码,先计算z-score和o-score,最后再计算QMJ因子。
def __call__(self):
第2-5行,读取资产负债表中的数据,主要是总资产、流动资产、流动负债、总负债、股东权益、盈余公积和未分配利润。这里的lag笔者设置为0Q,因为资产负债表的数据是直接使用的。
第6-7行,获取开始时间和标的集合,后续读取的数据都以这个为基准,这样就可以直接使用numpy数组进行计算了。
第8-10行,读取利润表的数据,主要是营业收入、财务费用、净利润和所得税。这里的lag需要设置为1Q,因为利润表需要用当前报告期的数据-上一报告期的数据才能得到单季度的值。
第11-15行,就是在计算单季度的营业收入、财务费用、净利润和所得税。
第16-21行,就是根据AI给的公式计算。其中营运资本=流动资产-流动负债;留存收益=盈余公积+未分配利润;息税前利润=净利润+财务费用——所得税。
第22-23行,计算z-score因子。
def __call__(self):
这个计算o-score的代码其实和上面是类似的,所以笔者就只讲关键点了。
第16-17行,笔者重新读了一次利润表。因为这次的lag设置为2Y,这样的话读取的就是过去两个财年的净利润数据。
第23行,就是用这两个数据来计算的因子值。
def __call__(self):
这段代码需要强调一下的就是29-31行,计算roe的波动。
3
因子收益率的计算
这个因子的因子收益率的计算与Fama-French三因子模型中的HML和SMB这两个因子相似,都是采用市值加权的方式。
同时,还通过市值将标的划分为Small和Big两个池子,具体的计算公式如下:

笔者认为,有了因子值之后,根据这个公式计算因子收益率应该是一件不难的事情,所以这部分代码就省略了。有需要的可以参考基于异常收益率的注意力捕捉,一个结合了涨跌停数量、Fama-French三因子模型和动量的超复杂因子!;这篇文章中的Fama-French三因子模型中因子收益率的计算代码。
因子评价
对于这个因子的因子评价结果,笔者是不报任何期待的。
因为,笔者在计算完z-score和o-score这两个因子之后,都对其进行了测试,但是效果都不好,就不来辣眼睛了。
当然,这个也同样辣眼睛。
01
IC分析






这个IC表现不谈了,一会儿正,一会儿负。
02
回归分析


03
换手率分析


04
收益分析


因子评价
复现这个因子的终极目的还是用它的因子收益率来分析基金的收益来源。所以,这篇文章发表出来的最大目的是为了基金收益率拆解服务的。
对于选股来说,这个效果真的是一言难尽了。