作者简介:
祝小宇,个人公众号:大猫的R语言课堂
前文推送:
35行代码搞定事件研究法(上)
Hello亲爱的小伙伴们,上期已经讲到如何对单一事件日计算超额收益,本期将会教大家如何针对多个股票多个事件日计算超额收益,Let's go!
注意 I,本代码主要使用data.table包完成,关于data.table包的相应知识会在涉及的时候进行讲解。在以后的课堂中,我们会重点介绍data.table这个包。
注意 II, 本代码还使用了partial()函数,它来自于pryr这个包
本期课堂的核心代码只有下面5行(应用了data.table包的语法):
虽然看起来似乎有些难懂,但如果我们将他分解为三部分,理解起来就容易多了。
首先,这5行代码可以抽象为如下形式:
其中,event数据集就是我们在上节课讲到的包含有股票代码、日期、股票收益率、市场收益率、事件日标识的数据集(什么你忘了?快去看上节课教程!就是那个黑色的图)。请观察在上面这个抽象后的代码,大家应该可以看出我们对event数据集做了三件事情,具体分别为:
选取event中所有的行(第一行代码)。此处,我们没有添加任何条件,因此默认选中event的所有行。
对选中的变量进行操作(第二行代码)。此处,所有的操作都用大括号{}包裹了起来。
对event按照stk.id进行分组(第三行代码)。加了这一行代码后,第二行代码中所有的操作都会对每个stk.id分组运行一遍(这一步很关键!)。
讲到这,大家一定会发现,上述代码的关键部分就在大括号{...}所括起来的内容。我们一行一行来看:
这一行代码的作用找到每个股票的所有事件日的序号 ns。大家应该还记得在上一讲中我们用 n 来表示单一事件日的序号吧?在这里,which(event.flg == 1)的意思是返回所有event.flg变量等于1的那些行的序号,很自然的,在这里 ns 应该是一个向量。
在上一讲中,我们已经给出了函数 do_car() 用来求单个事件日的超额收益,因此很自然的,我们希望对于事件日向量 ns 中的每个元素,都应用一遍 do_car()这个函数。为了做到这一点,我们运用了lapply() 函数。因此代码就变成了
那么,在最初给的那段代码中,partial()函数是用来干什么的呢?在这里我们不妨先回忆一下上一讲中的do_car() 函数有哪些参数:
看到了没有?do_car() 要求我们提供n, r, rm, date 四个参数,但是向量 ns 只能提供 n 这一个参数的值,因此我们需要用pryr包中的partial() 函数把剩下的几个变量补充完整(感谢pryr的作者Hadley!如果不是你,我们需要写许多非常冗长的代码)。
最后,将处理的结果赋值给car,我们的任务就完成了!下图是最终的输出结果(部分):
其中,stk.id是股票代码,date是事件日(非事件日不输出结果),coef是该事件日对应的收益率模型的系数(alpha、beta),ars是对应的超额收益率。在我们的例子中,我们只计算T日前后各一日的收益,因而ars一共有三个元素。
到此为止,求超额收益的计算就完成了,现在大猫给出完整的代码:
最上面三行注释用来描述数据结构,如果去掉的话,所有代码加起来35行都不到,是不是很神奇!
大猫在这里给出的代码已经经过高度优化,是在尝试众多可行方法后给出的计算速度最快的版本。小伙伴大可不必担心自己的数据太多计算机跑不起来。但是口说无凭,大猫在这里给出用模拟数据得到的测试结果。
在测试中,大猫设置了一个极端条件:模拟2500个股票(差不多是A股股票数),每个股票拥有1000个交易日的记录(差不多有4年的时间),平均50个交易日出现一个事件(模拟盈利公告这类事件的出现频率)。因此在整个数据集中,一共有250万条观测,5万个左右的事件。一般的事件研究法的数据量极少超过这个量级。
在这里附上生成模拟数据集的代码:
我们接着设定 c1 = c2 = 1, m1 = 90, m2 = 5,也即求 [T - 1, T + 1] 区间的超额收益,并用 [T - 90, T - 5] 这个区间估计收益率模型。这也是一个比较常见的设定。
大猫用这个数据集在自己的surface pro 4 i5版上连续跑了三遍,每一次的耗时分别为:
79s 81s 82s
三次平均耗时在80秒左右。可以说,这是一个非常优秀的成绩了。况且我们平时遇到的数据集应该远远小于模拟数据集,小伙伴还担心什么嗯?
既然已经算出了超额收益AR,那么下面我们自然希望把AR加起来得到累计超额收益CAR并进行T检验。例如,我们想知道每个事件日对应的累计超额收益,那么代码就为:
其中,car数据集是上面计算得到的所有事件日对应的超额收益率。语句“car :=” 表示在原数据集中新建一个名为 car 的变量,vapply(ars, sum)的含义是把超额收益率向量ars中的元素相加,double(1)指定输出的必须是一个标量(因为对于每个事件日,CAR是唯一的)
再比如,如果我们想计算逐日的累计超额收益率,那么代码就为:
cumsum() 是累计求和函数。注意,此时最终得到的cunsum应该是一个和ars长度相等的向量。
如果我们希望对每个股票的CAR进行T检验,那么代码就为:
最终的结果为:
其中,t.test给出了 t 值,p.ttest 给出了对应的p值。
其实,还有很多别的后续工作可以扩展,大猫就不一一介绍啦,小伙伴们可以自行实验。最后,如果觉得大猫的R语言课堂有用,请多多支持关注哦!
公众号后台回复关键字即可学习
回复 爬虫 爬虫三大案例实战
回复 Python 1小时破冰入门
回复 数据挖掘 R语言入门及数据挖掘
回复 人工智能 三个月入门人工智能
回复 数据分析师 数据分析师成长之路
回复 机器学习 机器学习的商业应用
回复 数据科学 数据科学实战
回复 常用算法 常用数据挖掘算法