2.2 合成5分钟数据
有些人问为什么需要合成5分钟数据?其实这更多是从研究效率来考虑。5分钟K线有以下几个好处。
(1)过滤了分笔数据的很多噪音。分笔数据的量非常大,但行情起起伏伏,很多是噪声交易者所为,并不能预示未来的趋势。因此,如果能把这些信息整合起来,可以起到减少噪声的作用,而且太微观的变化对持仓长线的策略并没有太大意义,性价比不高;
(2)提高计算速度。500毫秒的分笔数据5分钟可以有5×60×2=600个数据,如果使用5分钟K线,数据量只有原来的1/600,可以大大减少计算量;
(3)频率也不会太低。如果用频率更低的15分钟线,则可能会因为频率太低而失去很多交易的机会。国内商品市场上午10:15—10:30有个空档,而且上午是到11:30,下午1:30开始,因此划分K线最好是15的约数,10分钟其实也不大好,比如15分钟的空档很难处理;如果是半小时、一小时,则会出现跨越很多空档时间段,因此5分钟是比较好的选择。其实15分钟的因子都可以用5分钟合成。但1分钟或许太过密集,很多商品不活跃,1分钟也不会有太多成交。
合成5分钟K线数据主要包括开始价、最高价、最低价、结束价、成交量、成交额、持仓量等信息,这些都是500毫秒数据包含的,只需简单处理一下。但需要注意的地方包括:
(1)并不一定在整5分钟结束的时候有行情。比如这段rb1709的行情:
在加粗部分,直接从21:04:58.500跳到了21:05:00.500,而应该存在的21:05:00.000却不存在。因此,在进行K线分割时,并不能机械地查找整5分钟的时间点,而应该顺着行情一个一个检查。
(2)每个合约开始结束时间并不一样。比如黄金、白银是凌晨2:30结束,而很多品种没有夜盘,有的品种夜盘的时间在历史上修改过,因此,程序要能灵活识别这些情况。比如把数据分段,如果该段不存在行情,则应该知道该品种在那个时段是没有交易的。在这里,把夜盘分成5段,因为白天都是一样的,所以只有一段,因此,程序可以这么写:
注意到,比如是23:00:00.500这个时间,它会属于night.2,某些品种夜盘会在这个时刻结束,因此,如果用“<23:00:01”的条件可以把它包含进来。每天结束时有时会有15:00:00.500的时刻,因此用“<15:00:01”可以把它包含进来。
(3)程序运行速度。无论R语言、Matlab,还是Python,其实都是解释性语言,运行速度较慢,如果处理一些难以向量化的运算则会力不从心,此时可以考虑用C++来写。
2.2.1 R语言的版本
比如上一小节说的找出每个5分钟的切割点,如果用R语言来写,可以写成如下函数:
可以重复1000次考察其运行时间:
由此可以看出,效率并不是十分高。主要原因在于R语言本质上是解释性语言,对于循环语句来说运行速度很慢,而这类切割K线存在路径依赖的问题,很难并行化处理。因此,要想提高速度,只能使用其他速度更快、更低级的编程语言来实现。
2.2.2 结合Rcpp提速
目前最常见的低级语言是C和C++,它们速度差不多,但C++更容易上手,而且有着面向对象的功能,在R语言里面也可以直接调用,无缝连接。
R语言有一个专门跟C++程序结合的包叫做Rcpp,使用这个包可以直接在R语言里面编译C++的程序,甚至可以自己专门建立一个library,每次方便调用。因此,如果读者熟悉C++的话,不妨尝试一下。
如果这部分用C++来写,结合Rcpp,可以新建一个程序文件getTimeSplit.cpp:
如果要调用里面的命令,需要先用sourceCpp()命令来编译:
然后可以看看用Rcpp的效果:
我们可以对比一下R和Rcpp运行的结果:
可见,两种语言运行的结果是一样的,但Rcpp的速度相比R语言要提高数十倍。
因此,提高计算速度对提高研究速度是非常有帮助的。比如80年代的神经网络,虽然模型拟合能力非常厉害,但由于当时的数据集并不是很大,很容易过度拟合。而且复杂的模型需要的参数比较多,即使有大量的数据集,运算一遍非常耗时,以至于研究者缺乏足够的耐心进行参数优化。90年代的支持向量机等算法虽然在拟合能力上不如神经网络,但是却采用了大量的数值计算、数值优化技巧,使运算速度大为提高,反而能够在那个年代脱颖而出。
然而,2010年以后,随着GNU等并行计算的大规模普及,以及互联网等大规模数据的产生,很多计算量大的模型反而重新获得了生命力。由于传统神经网络模型的名声不是那么好,神经网络的研究者采用了一个新的名字“深度学习”来继续他们的研究。
事实上,深度学习是在神经网络上发展起来的,比如著名的深度学习模型卷积神经网络(Convolutional Neural Network,CNN)则更是跟神经网络高度相关,所不同的地方在于普通的神经网络要自己找出因子,然后放入模型中学习,而卷积神经网络可以自己主动去寻找因子。这主要应用于图像分类中,比如要识别出一只动物是猫还是狗,一开始的分层更多是一些边界轮廓,比如识别出头部,然后逐步深入,可以识别出眼睛、嘴巴等,卷积类似于信号处理的滤波,可以把图像不同频率的特征识别出来,一开始是一些比较低频的特征,然后是更为高频的特征,最后再把这些特征放入神经网络模型中去拟合。
那么,这类模型能否用来分析金融数据呢?这个问题后面的章节会提到,这里只提一些思路。比如金融时间序列也是有低频和高频之分的,低频的更能显示出趋势,高频的则更类似于数据中的“毛刺”。比如一个5分钟K线,开盘价和收盘价构成主体,类似于主要趋势部分;上尾和下尾则类似于毛刺部分。或许一些厉害的高手可能把整个金融时间序列进行分解,比如是把价格变化分解成高频交易员产生的部分、低频交易员产生的部分、基本面产生的、技术面产生的等几个部分,类似于猫的头部、身体、尾部等然后再加总起来。
各个部分的交易员一般不会频繁改变自己的交易思路,并且市场中各部分成员的比例在短时间内也不会改变,即使缓慢改变,我们也可以通过渐进式(adaptive)的模型去拟合,这种方式或许比目前简单的线性回归模型更好一些。当然,这类模型需要的数据量也会更多,或许可以把数十个品种的数据加起来进行拟合。其实,每个分笔数据类似于图像处理的每个像素点,或许可以把图像处理的模型移植到金融中。这些内容已经超出了本书的范围,不再深入研究,它的计算量会比目前的模型大得多。我们接下来讲解运用多核并行计算来提高计算速度。
2.2.3 多核并行再次提速
如果是处理单个品种的数据,用Rcpp进行提速似乎已经很不错了。但商品期货有数十个品种,而且品种数目一直在增加,我们应寻求其他提高速度的办法。
现在的计算机普遍采用了多核CPU,每核一般有两个线程。比如本人现在使用的笔记本计算机是2核4线程,使用的台式机是10核20线程,当然服务器可以有几百个线程,国外厉害的公司估计几千个线程都没问题。使用这些来进行编程,自然可以更好地提高速度。
比如,在R语言里面可以使用parallel包来实现并行计算:
如果使用更多的核来并行,可以进一步提高速度。这里makeCluster()是使用核的命令,n.core是核的数目,这里是4。另外,parLapply()是并行的命令,par开头的此类处理命令在parallel包里面。
下面看看parallel.process.5m.data()的程序:
之所以对郑州单独处理是因为大连和上海的合约月份都是4位,而郑州是3位。这里面还调用了一个函数parse.dire.fast(),它是对一个文件夹里面的所有合约进行处理,代码如下:
这里面调用了函数get.data.5m.fast(),它就是利用了Rcpp的函数来把分笔数据整理成5分钟数据,速度比较快,代码如下:
这里计算了5分钟K线的高开低收以及成交量、持仓量等,至此,整个把分笔数据合成5分钟K线的程序就完成了。如果该品种某段交易时间段不交易,则会自动跳过该段时间段,进入到下一个时间段。哪怕该段时间只有一次交易,也会生成该段所有的5分钟K线。
当然,这个程序也有一定的缺陷,比如交易所改变交易时间段,增加某些时间段或拆分已有的时间段等都需要修改程序。
另外,部分量化交易策略需要估算挂单成交的,除了高开低收的成交价以外,还需要挂单价,这里由于我们分析的是趋势策略,加滑点抢单成交,并没有分析被动挂单策略,因此不需要最高价和最低价的挂单价,有兴趣的读者可以自己整理一下。