一、实验介绍--订单流数据描述分析
1.1 实验知识点
- 订单流数据表示
- 订单间隔分析
- 订单信息率平稳性研究
- 订单流动性研究
- 限价单相对价格分析
1.2 实验环境
- R 3.4.1
- Rstudio
二、订单流数据描述分析
2.1 订单流数据表示
当我们在金融市场上做交易时 , 可以看到一个委托单簿,上面陈列着买价和卖价以及它们对应的量 ,
举个例子,比特币市场的订单簿:
可以看到红色代表的是卖价,或者说是 ask , 而绿色代表的是买价 , 或者说是 bid 。 在众多买卖价中 , 最高的买价和最低的卖价是比较重要的两个价格 ,分别被称为最佳买价和最佳卖价 , 即时价格也一般在这两者之间。
这个订单簿在不停地变化 , 有的时候买价和卖价上的量变少了 ,这是由于卖单或买单与它成交,这类即时成交的订单被称为市价单。 另外我们也可以挂单 , 那么订单簿上可能出现新的价格 , 或者使旧价格的量变大 , 这类订单被称为限价单。
这些类型订单一起组成了订单流,本文使用的数据是处理过后的美国标普 500 期货一天的交易数据, 我们可以看看订单流具有哪些统计特征。
dat <- read.csv(url("http://labfile.oss.aliyuncs.com/courses/883/pigu.csv"))
summary(dat[,2:ncol(dat)])
## action_item action_type ask_price ask_vol
## ask:1234169 A: 10040 Min. :145675 Min. : 1.0
## bid:1265295 M:2489424 1st Qu.:146050 1st Qu.: 185.0
## trd: 285548 T: 285548 Median :146200 Median : 443.0
## Mean :146223 Mean : 602.7
## 3rd Qu.:146400 3rd Qu.: 860.0
## Max. :146825 Max. :3742.0
## bid_price bid_vol price time
## Min. :145650 Min. : 1.0 Min. :145425 Min. :1.358e+09
## 1st Qu.:146025 1st Qu.: 188.0 1st Qu.:146025 1st Qu.:1.358e+09
## Median :146175 Median : 459.0 Median :146200 Median :1.358e+09
## Mean :146198 Mean : 575.6 Mean :146210 Mean :1.358e+09
## 3rd Qu.:146375 3rd Qu.: 843.0 3rd Qu.:146400 3rd Qu.:1.358e+09
## Max. :146800 Max. :3545.0 Max. :147050 Max. :1.358e+09
## vol
## Min. : 1
## 1st Qu.: 219
## Median : 634
## Mean : 839
## 3rd Qu.:1378
## Max. :4255
先来看一看每个变量的统计, action_itme 的含义是订单类型 , 其中 “M” 代表对 order book 的改变 , 换句话说就是限价单;而 “T” 代表的是 trade ,也可以说是市价单。 ask price 和 ask vol 分别代表最优卖价和量 , bid price 和 bid vol 分别代表最优买价和量 。 price 和 vol 分别代表订单对应的价格和量。 time 是以 1970 年开始计算的秒数。
head(dat)
## X action_item action_type ask_price ask_vol bid_price bid_vol price
## 1 0 bid M 146500 101 146500 105 146400
## 2 1 bid M 146500 101 146500 105 146325
## 3 2 bid M 146500 101 146500 105 146300
## 4 3 ask M 146500 101 146500 105 146525
## 5 4 ask M 146500 101 146500 105 146550
## 6 5 ask M 146500 102 146500 105 146500
## time vol
## 1 1358203997 108
## 2 1358203999 106
## 3 1358203999 179
## 4 1358204012 42
## 5 1358204015 147
## 6 1358204016 102
format(head(dat)$time,digits=21)
## [1] "1358203996.7088456" "1358203999.3707500" "1358203999.4706881"
## [4] "1358204012.2595844" "1358204014.8965719" "1358204016.0976164"
我们看一看时间的精度 , 达到了10的负7次方 , 也就是达到了微秒级。
as.POSIXct(head(dat)$time[1],origin="1970-01-01",tz="America/Chicago")
## [1] "2013-01-14 16:53:16 CST"
我们用函数将其转化为 R 语言中的时间格式 , 发现首个数据的时间是下午 5 点。
library(tidyverse)
library(lubridate)
bisect_lower_bound <- function(x) {
date <- as.POSIXct(x[1],origin="1970-01-01",tz="America/Chicago") + days(1)
hour(date) <- 8
minute(date) <- 30
second(date) <- 0
k <- as.numeric(date)
l = -1
r = length(x)+1
while(r-l>1) {
mid = round((l+r)/2)
if (x[mid] >= k) r=mid
else l=mid
}
r
}
bisect_higher_bound <- function(x) {
date <- as.POSIXct(x[1],origin="1970-01-01",tz="America/Chicago") + days(1)
hour(date) <- 15
minute(date) <- 0
second(date) <- 0
k <- as.numeric(date)
l = -1
r = length(x)+1
while(r-l>1) {
mid = round((l+r)/2)
if (x[mid] <= k) l=mid
else r=mid
}
l
}
start <- bisect_lower_bound(dat$time)
end <- bisect_higher_bound(dat$time)
trade <- dat[start:end,]
由于美国标普 500 的交易时间是上午 8 点半到下午 3 点 , 我们用一个二分搜索把交易时间内 的数据提取出来,并命名为 trade , 下面我们就来对 trade 进行一些探索。
2.2 订单间隔分析
订单和订单之间的间隔是怎么样的?间隔一般有多长?间隔会服从什么分布? 要回答这些问题我们对订单的间隔做一些统计分析。
time <- trade$time
time_diff <- diff(time)
time_diff <- time_diff[time_diff>0]
summary(time_diff)
## Min. 1st Qu. Median Mean 3rd Qu. Max.
## 0.0000112 0.0003750 0.0011960 0.0262100 0.0192800 2.2140000
可以看到 75 分位数和均值大约 0.02s , 这可以说明标普 500 期货的交易非常频繁,流动性非常好。
hist( time_diff[time_diff<0.1] , breaks=seq(0,0.2,0.001) ,xlim=c(0,0.1),probability=TRUE, col="gray", border="white" , xlab="empirical ")
上面是订单间隔的分布图,由于大于 0.01s 的间隔较少,我们选取小于 0.01s 的间隔进行可视化,可以观察到分布是高度有偏的,绝大多数间隔都非常小。
library(MASS)
time_diff_p <- time_diff[time_diff<0.04]
exp_fit <- fitdistr(time_diff_p,densfun="exponential")
exp_ran <- rexp(length(time_diff_p), rate = exp_fit$estimate)
plot(density(exp_ran) , ylim=c(0,700) , main="inter-arrival time: empirical vs exponential" , xlab = "inter-arrival time")
lines(density(time_diff_p), col="red")
用指数分布去拟合小于 0.04 的订单间隔,发现实际数据衰减的速度远远高于对应最优参数模拟指数分布衰减的速度。由于指数分布的衰减速度是非常快的,这更说明小间隔的比例有多么大,可以说这是实实在在的“高频”交易。
做市商的存在证据
高频交易中有一类交易者叫做做市商,它们在市场中挂买单和卖单,如果都成交了就可以赚取 其中的价差。它们一般下限价单,为市场提供流动性,当然它们也会有一些自己的策略,例如在市场上出现市价单时做市商一般会调整自己的订单,所以他们会马上下跟踪的限价单,我们从统计来看一看市场有没有这样的现象。
action <- trade$action_type
pre <- action[1:(length(action)-1)]
aft <- action[2:length(action)]
market_maker <- intersect(which(pre=="T") , which(aft=="M"))
mm_diff <- time[(market_maker+1)] - time[market_maker]
mm_diff <- mm_diff[mm_diff>0]
plot(density(time_diff), col="red",xlim=c(0,0.01),ylim=c(0,5000) , main="The evidence of market maker")
lines(density(mm_diff) , col="green")
我们筛选出了这种特殊的间隔,即前面的事件是市价单,后面的事件是限价单,我们把这种间隔的分布用绿色的线画出来,可以看到这种类型的跟单速度比普通的跟单速度快得多,其峰值小于1毫秒,真是称得上是快如闪电。
2.3 信息率的平稳性
下面我们来看一看订单的到来,或者说是信息率是否是平稳的。我们回忆一下泊松过程,在泊松过程中,对于一个 t 的间隔和 nt 的间隔,它们都服从泊松分布,只是后者的参数是前者的 n 倍 , 所以如果我们统计 t 间隔事件数的分布与 nt 间隔事件数的分布,对应分位数的事件数后者应该是前者的 n 倍,那么在实际数据中是不是这样呢?
由于我们一般关注的是信息率比较高(订单来得比较快)的时间段,这些时候是标的价格变动比较剧烈的时间段,所以我们观察较高的分位数对应的事件数。
quantile(c(table(cut(time, breaks = seq(min(time)-1, max(time)+1, by = 1)))) , c(.9,.99,.999,.9999,.99999))
## 90% 99% 99.9% 99.99% 99.999%
## 140.000 733.000 1276.800 2451.220 2935.258
quantile(c(table(cut(time, breaks = seq(min(time)-0.01, max(time)+0.01, by = 0.01)))) , c(.9,.99,.999,.9999,.99999))
## 90% 99% 99.9% 99.99% 99.999%
## 1.0 10.0 89.0 307.0 406.2
我们选取的是 1s 和 0.01s , 如果是平稳的那么 0.01s 对应的分位数应该是 1s 的百分之一左右。但是实际上在越高的分位数上这个规律就越不成立 ,在 99.99 分位和 99.999 分位上甚至超过了十分之一。
这说明事件的到来有高度聚集的特征,不能简单地用泊松过程来刻画 。
2.4 流动性研究
流动性的含义是当你想交易时,你是否有能力快速地进行大规模交易。它由三个要素组成,速度,深度和宽度。
深度主要与订单量有关,两方的订单量越多,能够承受的买压或卖压就更大,流动性就更好
而宽度主要与价格有关,在市场中我们可以看到一些交易量小的标的,它的 bid 和 ask 的距离非常之大,这样如果我们用市价单一买一卖,会有较大的损失,而对于一些交易量大的标的,bid 和 ask 的距离可能非常小,可以放心下市价单进行即时交易。
由于我们的数据里只有最优买价和最优卖价,没法对深度进行分析,我们只能通过分析 bid 和 ask 的距离(这个距离被称作 spread)来分析一下宽度。
plot( time ,trade$ask_price , col=adjustcolor("red", alpha=0.2) , type='l' , ylab = "bid and ask" , xlab="time")
lines(time , trade$bid_price , col=adjustcolor("blue", alpha=0.2) )
从图中我们可以看到 bid 和 ask 始终贴合得非常紧,没有出现特别大 spread 的情况,下面从数值上看一看 spread 的分布。
table(trade$ask_price - trade$bid_price)
##
## 0 25 50 75
## 90 1767344 6531 1
可以看到绝大多数时候 spread 都是 25(1 个 tick) ,说明标普 500 期货 的流动性非常之好。
2.5 限价单相对价格分析
当在准备下限价单时,我们有很多选择,可以当一个保守的人,下一个离最优价格很远的单子,也可以下离最优价格很近的单子,这样很大概率能够快速成交。
我们把相对价格定义为
bid_relative_price = (best bid - 下单价格) / tick
ask_relative_price = (下单价格 - best ask) / tick
这样可以做一个统计,来看一看限价单相对价格的统计分布。
ask_pre <- trade$ask_price
ask_idx <- which(trade$action_item=="ask")
relative_ask <- (trade$price[ask_idx] - trade$ask_price[(ask_idx-1)])/25
bid_idx <- which(trade$action_item=="bid")
bid_idx <- bid_idx[2:length(bid_idx)]
relative_bid <- -(trade$price[bid_idx] - trade$bid_price[(bid_idx-1)])/25
plot(density(relative_ask) , col="red" , main="relative price for bid and ask" , xlab="relative tick")
lines(density(relative_bid) , col="blue")
从图中我们可以看到 , 买单和卖单的相对价格分布基本相同 ,大多限价单的相对价格都在 0,1,2 左右。
prop.table(table(relative_ask))
## relative_ask
## -2 -1 0 1 2
## 1.277931e-06 1.529683e-03 5.584762e-01 1.701693e-01 5.857651e-02
## 3 4 5 6 7
## 3.287988e-02 3.040325e-02 3.097832e-02 3.253484e-02 3.188693e-02
## 8 9 10
## 2.404938e-02 2.694517e-02 1.569299e-03
prop.table(table(relative_bid))
## relative_bid
## -1 0 1 2 3
## 6.411562e-04 5.797784e-01 1.624503e-01 5.720074e-02 3.407865e-02
## 4 5 6 7 8
## 2.854599e-02 3.290509e-02 2.960826e-02 2.719286e-02 2.062828e-02
## 9 10 11
## 2.544644e-02 1.522588e-03 1.264608e-06
我们也可以用数值检验一下结果。
三、 总结
在前面的内容中,我们从各个方面对订单流数据进行了统计分析,下面我们要进入的是建模环节。