伦敦 伦敦00:00:00 纽约 纽约00:00:00 东京 东京00:00:00 北京 北京00:00:00
当前位置:主页 > 投资学院 > 交易策略 >
交易策略

皮尔逊相关系数实现相似K线及其性能优化

  后文代码摘录进本文时已经剔除了业务层代码,仅展示核心计算逻辑。以下数据结果均为2017-08-28运行得到。并且以下计算仅为单支股票的历史数据遍历,没有完整的运行全市场的数据,遍历全市场的时间消耗可以通过单支股票的运行时间估算得到。在下文特例中,就是对比600570.SS最新30天的数据和600571.SS历史所有数据的相似度。

  其实对于大部分数据段,在任何一支上市五六年以上的股票历史数据上都可以找到相似度大于0.9的数据段,大家在许多产品上看到的排名前几位的相似K线也仅仅只是沧海一粟,对应的后期走势也不可能代表所有数据情况,所以笔者在此对相似K线的有效性仍然持怀疑态度。什么意思呢,对于一段数据,查找出的一个相似K线提示未来价格上升,而另一个相似K线则提示未来价格下跌,那投资者如何判断?并且这种分化走势是一定存在的,如果大家在某个产品上看到的相似K线%上涨,那只是这个产品没有把数据算全而已。相似K线只能提供形态上的模拟近似,并不能完整的将当前个股和历史数据的金融条件(消息面、基本面等)完全匹配。

  对于这个问题场景,有不有存在一种既节省空间有节省时间的算法存在呢?答案就是动态规划算法。

  本文就将简要先容如何实现相似K线的计算,并讨论实现过程中的一些难点细节。

  动态规划算法的详细先容可以从网上找到相关资料,本文对于概念只做简单先容。简单来说,动态规划就是指当前计算可以利用前一次的计算结果。对于皮尔逊公式,大家可以将中间计算过程存储下来,并在数据遍历的时候只变化头尾数据,这样就不需要保存所有相似度计算结果再到最后进行排序,而只需要维护一个长度为compareCount(本例中即30)的中间计算状态数组,在空间上解决了问题;由于每一步计算基于前一步计算的结果,因此除了第一步需要完整计算一个compareCount(本例中即30)的皮尔逊系数,后续每一次循环都只进行很少的“头尾替换”计算,因此理论上该算法在时间上的性能也是极优的。对于这个算法,大家也会得到全局最优解的精确解。程序代码如下:

  最简单的实现方法就是全市场计算,蛮力遍历,将得到的所有结果进行排序,最终得到相似K线:

  公式主要通过平均数和协方差的概念来计算相似度,实现较为容易。对于K线数据,输入X,Y就是一组连续的价格数据,通过计算皮尔逊公式,大家会得到一个-1~1的相关系数,结果越接近1的数据,相似度越高。以下代码是对上述公式的完整实现,编程使用JavaScript:

  为了降低计算量,然后对这前几位数据索引再进行完整计算:投资者可以根据相似K线展示的结果来观察个股可能的未来走势,皮尔逊公式将计算两组长度为30的数组数据的相似度。在此本文再给出一种经过“代码调优”之后的程序实现。最终得到了比蛮力遍历性能提升113倍(比算法四性能提升22倍)的计算程序。大家计算600570最新30天的数据,这种缺陷在进行全市场数据运算时将会暴露的更加凸显。第二部分是排名筛选。大家对冗余的循环进行合并、去除多余的方法栈调用、去除了多余的内存分配(Array.slice),算法本身是基于动态规划(算法四),在下面这套代码中,例如选取数组头、数组中、皮尔逊相关系数实现相似K线及其性能优化数组尾三个数据来计算相关度,对于本文中的特定案例,

  该算法唯一的缺点就是实现复杂。本身将简单的循环计算修改成动态规划循环就是一个不小的挑战;其次,在这个问题场景下,大家还需要修改对皮尔逊公式的实现,来保存中间过程,可以看到代码中大家使用calcAtom和calcPearson重写了皮尔逊公式的代码实现。

  由此,大家就得到了对比相似度的方法。下一步大家将要从全市场历史数据中找出相关度最高的相似K线数据。

  进行相似度匹配时大家使用“皮尔逊相关系数”(Pearson product-moment correlation coefficient)来进行相关度验证。详细的“皮尔逊相关系数”的推导及演算可从网上找到相关资料。本文大家直接使用结论公式:

  最近的量化很火,越来越多的国内外企业开始参与到其中,我相信量化是金融交易系统后续发展的大方向,其中一定有值得大家去挖掘和发现的价值和惊喜。根据自己的想法设计了一套K线历史数据比较和分析系统,算是量化中...博文来自:smallcat0073的博客

  基于上述讨论和测试(不考虑程序示例五,因为程序五不是一种算法设计技术,而是一种代码调优技术),得到以下算法性能结果:

  公式中,cut表示粗略计算后截取前多少名进行精确计算(本例中取值为100),compareCount表示整个对比数据的长度(本例中就是30),totalLength表示历史数据的长度(本例中600571历史数据长度为1404),divide表示特征数据个数(本例中用3个特征数代替30的完整数据)。对于这个公式,divide和cut是由开发人员主观定义的。divide越大,粗略计算的成本也就越高,当cut=compareCount时,这个算法也就退化成第一种蛮力遍历算法;cut越大,最后的精确计算成本也越高,但是注意cut不能太小,因为粗略计算过程中实际上是个贪婪计算过程,可能会遗失全局最优解而得到局部最优解。另一点要说明的是,该算法计算过程中也必须保存一个数据长度的相似度数组来进行最后的排序,因此空间消耗和第一种蛮力遍历算法一样大(可以通过维护一个长度为cut的降序数组保存相似度前几位的数据,来进行小幅度的优化,大约提升15%的性能)。

  可以看到,运行时间几乎得到了15%的性能提升。并且新的算法在空间上也更优。

  于是大家想到可以对排序进行优化:因为不会出现漏算的情况,大家在计算过程中只保存当前最高相似度数据的值,这样就节省了排序数组的空间和最后排序的时间:

  这种算法实现简单,并且得到的结果一定是相似度最高的数据。但是这种算法需要将所有数据完整遍历计算,并且过程中需要保存下每个数据的计算结果,最终排序后得到最相似的数据,从时间和空间角度来看性能极差。

  2020年全新Java学习路线图,含配套视频,学完即为中级Java程序员!!02-06

  单线分钟。相似K线的实现主要分为两大部分,如下图是某产品的相似K线效果图:对于生产级高TPS场景,大家从数组中选取几个特征数据,在粗略计算后选取相似度排名前几位,第一部分是相似度匹配计算;也就是说每次循环,介于此,从而对投资起到一定的引导作用。替代每次都完整计算整个数据的相似度,但是大家仍然无法避免大规模的数据运算,但是具体的实现形式从“面向对象”转向了“面向过程”。使用下面的程序进行全市场遍历计算,相似K线是验证“历史总会重演”的一个经典产品,虽然经过了优化,目前许多炒股App都开始陆陆续续提供相似K线功能。大家提出一种可行的优化算法:引入分治思想。


点击次数:  更新时间:2020-03-19 07:03   【打印此页】  【关闭
XML 地图 | Sitemap 地图