行列转换(pivot)是一个常见的整顿数据的需要,又称为转置或者透视。

高频数据通常以下图的格局保留:每一行为一个股票在某个时刻的信息。

咱们进行数据处理时,思考到后续的向量化操作,有时会心愿数据或者两头后果将原始数据转置,即每行代表不同的时刻,而每列代表一只股票。在DolphinDB中可通过pivot by语句对原始数据或分组聚合后果进行行列转置。若与向量化操作搭配应用,在高频数据处理和计算中,行列转换不仅可简化策略代码,还能进步代码效率。具体请看上面的两个例子。

  1. 计算股票收益的两两相关性

在配对交易(pair trading)及危险对冲(hedging)时,常常须要计算给定一篮子股票之间的两两相关性。这种简单的计算在传统的数据库中无奈执行,而应用个别的统计软件不仅须要数据迁徙,还须要繁琐的代码。上面咱们应用DolphinDB来计算股票收益的两两相关性。

首先,载入美股股票高频交易数据库:

quotes = loadTable("dfs://TAQ", "quotes")

接下来,抉择2009年8月4日中500只报价变动最频繁的股票:

dateValue=2009.08.04num=500syms = (exec count(*) from quotes where date = dateValue, time between 09:30:00 : 15:59:59, 0<bid, bid<ofr, ofr<bid*1.1 group by Symbol order by count desc).Symbol[0:num]

上面咱们利用pivot by将高频数据降维成为分钟级数据,并且扭转原始数据的构造,生成一个分钟级股票价格矩阵:每一列是一只股票;每一行是一分钟。

priceMatrix = exec avg(bid + ofr)/2.0 as price from quotes where date = dateValue, Symbol in syms, 0<bid, bid<ofr, ofr<bid*1.1, time between 09:30:00 : 15:59:59 pivot by time.minute() as minute, Symbol

DolphinDB的语言非常灵活。在这里,pivot by不仅将数据转换为透视表,同时也能够搭配聚合函数应用,具备"group by"的性能。

利用高阶函数each将价格矩阵转换为收益率矩阵:

retMatrix = each(def(x):ratios(x)-1, priceMatrix)

利用高阶函数pcross计算这500只股票之间收益的两两相关性:

corrMatrix = pcross(corr, retMatrix)

选取与每只股票相关性最高的10只股票:

mostCorrelated = select * from table(corrMatrix).rename!(`sym`corrSym`corr) context by sym having rank(corr,false) between 1:10

选取与SPY相关性最高的10只股票:

select * from mostCorrelated where sym='SPY' order by corr desc

quotes总共有2,693亿条数据,2009年8月4日这天一共有近1.9亿条数据,执行下面的计算,耗时仅需1,952毫秒

  1. 计算股票组合的价值

在进行指数套利交易回测时,须要计算给定股票组合的价值。当数据量极大时,回测时采纳个别数据分析系统,对系统内存及速度的要求极高。而DolphinDB database 从底层进行优化,对硬件的要求不高。

在本例中,为了简化起见,假设某个指数只由两只股票组成:AAPL与FB,工夫戳精度为纳秒,指数成分权重存在weights字典中。

Symbol=take(`AAPL, 6) join take(`FB, 5)Time=2019.02.27T09:45:01.000000000+[146, 278, 412, 445, 496, 789, 212, 556, 598, 712, 989]Price=173.27 173.26 173.24 173.25 173.26 173.27 161.51 161.50 161.49 161.50 161.51quotes=table(Symbol, Time, Price)weights=dict(`AAPL`FB, 0.6 0.4)ETF = select Symbol, Time, Price*weights[Symbol] as weightedPrice from quotesselect last(weightedPrice) from ETF pivot by Time, Symbol;

运行后果如下:

Time                          AAPL    FB----------------------------- ------- ------2019.02.27T09:45:01.000000146 103.9622019.02.27T09:45:01.000000212         64.6042019.02.27T09:45:01.000000278 103.9562019.02.27T09:45:01.000000412 103.9442019.02.27T09:45:01.000000445 103.952019.02.27T09:45:01.000000496 103.9562019.02.27T09:45:01.000000556         64.62019.02.27T09:45:01.000000598         64.5962019.02.27T09:45:01.000000712         64.62019.02.27T09:45:01.000000789 103.9622019.02.27T09:45:01.000000989         64.604

因为工夫戳精度为纳秒,基本上所有交易的工夫戳均不统一。如果回测时的数据行数极多(几亿或几十亿行)且指数成分股数量也较多(如S&P500指数的500只成分股),应用传统剖析零碎,要计算任一时刻的指数价值,须要将原始数据表的3列(工夫,股票代码,价格)转换为等同长度然而宽度为指数成分股数量+1的数据表,向前补充空值(forward fill NULLs),进而计算每行的指数成分股对指数价格的奉献之和。这种做法,会产生比原始数据表大很多倍的两头过程数据表,很有可能会导致系统内存不足。同时,计算速度也很慢。

应用DolphinDB的pivot by语句,只须要一行代码,即可实现上述的所有步骤,代码简洁,而且无需产生两头过程数据表,无效防止内存不足的问题,同时极大晋升计算速度。

select rowSum(ffill(last(weightedPrice))) from ETF pivot by Time, Symbol;

后果如下:

Time                          rowSum----------------------------- -------2019.02.27T09:45:01.000000146 103.9622019.02.27T09:45:01.000000212 168.5662019.02.27T09:45:01.000000278 168.562019.02.27T09:45:01.000000412 168.5482019.02.27T09:45:01.000000445 168.5542019.02.27T09:45:01.000000496 168.562019.02.27T09:45:01.000000556 168.5562019.02.27T09:45:01.000000598 168.5522019.02.27T09:45:01.000000712 168.5562019.02.27T09:45:01.000000789 168.5622019.02.27T09:45:01.000000989 168.566

DolphinDB下载:DolphinDB

应用过程中有任何问题,欢送退出智臾科技:DolphinDB技术交换群,内含二维码