R語言對高頻交易訂單流進行建模分析 4
一、實驗介紹--訂單流模型擬合
1.1 實驗知識點
- 指數核 hawkes 過程擬合
- 正反饋強度分析
- 訂單量影響分析
1.2 實驗環境
- R 3.4.1
- Rstudio
二、訂單流模型擬合
在上節中我們對訂單流資料做了一些統計分析 , 對交易的一些特徵有了一些粗淺的理解 , 在本節中 我們要做的是利用實際資料來擬合 hawkes 過程 ,看一看真實資料的訂單流動力學中有什麼特徵。
首先我們仍是選出交易時間內的資料:
library(tidyverse) library(lubridate) dat <- read.csv(url("http://labfile.oss.aliyuncs.com/courses/883/pigu.csv")) 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,]
2.1 指數核 hawkes 過程擬合
形象地來看,限價單組建起了買方和賣方的堡壘,而市價單則對對手的堡壘發起衝擊。
那麼作為進攻部隊,市價單對買方賣方力量的博弈是非常關鍵的,在本節中我們就單獨看一看市價單的動力學是怎麼樣的。
我們先把所有的市價單單獨提出來:
market_order <- trade[trade$action_type=="T",]
head(market_order)
## X action_item action_type ask_price ask_vol bid_price bid_vol
## 959396 959395 trd T 145925 643 145900 364
## 959397 959396 trd T 145925 640 145900 364
## 959413 959412 trd T 145925 642 145900 372
## 959414 959413 trd T 145925 642 145900 366
## 959415 959414 trd T 145925 642 145900 365
## 959416 959415 trd T 145925 642 145900 364
## price time vol
## 959396 145925 1358260200 3
## 959397 145925 1358260200 3
## 959413 145900 1358260200 1
## 959414 145900 1358260200 6
## 959415 145900 1358260200 1
## 959416 145900 1358260200 1
然後做一些預處理,把時間相同的訂單進行合併,並把所有時間減去初始值
m <- market_order %>% group_by(time) %>% summarise(sum(vol))
time <- m$time - m$time[1]
vol <- m$`sum(vol)`
首先我們不考慮訂單量的大小,把所有買單賣單視作同質的,用指數核的 hawkes 過程進行擬合,
這裡可以直接使用第二節所用的似然函式,然後用 nlminb 函式做優化:
log_likelihood <- function(params , event) {
mu = params[1]
alpha = params[2]
beta = params[3]
n = length(event)
t_n = event[n]
kernel_sum <- numeric(n)
for (i in 2:n) {
kernel_sum[i] = (kernel_sum[i-1]+alpha) * exp(-beta*(event[i] - event[i-1]))
}
lambda <- kernel_sum + mu
L = sum( log(lambda) ) - mu * t_n - alpha*n/beta + alpha/beta*sum(exp(-beta*(t_n-event)))
#print(L)
-L
}
nlminb(c(1,1,1) , log_likelihood ,event= time)
## $par
## [1] 1.522979 145.265214 368.465284
##
## $objective
## [1] -80224.79
##
## $convergence
## [1] 0
##
## $iterations
## [1] 39
##
## $evaluations
## function gradient
## 44 131
##
## $message
## [1] "relative convergence (4)"
擬合得到的 beta 的值非常大,說明前面事件對後面事件的影響衰減得非常快。注意 1/beta 被定義為 Hawkes 過程的記憶時間 , 超過這個時間的後續事件基本不受這個事件的影響 。 這裡我們可以看到影響週期小於一毫秒 , 說明頻率確實非常快。
2.2 正反饋強度分析
索羅斯在他的“金融鍊金術”中提出了一種叫做 reflexity(自反性)的理論 , 這個理論說的是投資者和交易者的認知偏差會改變標的的基本面。例如一支股票持續上漲,會使得投資者對提高對它基本面的認知 ,又反過來推動股價的進一步上升, 從而形成正反饋。
但是如何量化地對正反饋進行分析一直是一個問題。在 Hawkes 過程中,根據 lambda 的表示式我們可以把事件發生的強度分為兩部分 , 一部分是背景的強度 , 一部分則是由前面事件激發而得到的強度,這部分“衍生”的強度的平均值可以被認為是正反饋的強度。
例如在指數核中,我們可以通過積分計算出正反饋機制的比例是 alpha / beta , 下面我們把一天的時間按照30分鐘的間隔分為13段 , 看看每一段的背景強度和 reflexity 分別是多少。
time_cut <- cut(time , breaks = seq(-0.01 , time[length(time)]+0.01 , length.out=14) )
reflexity <- as.data.frame(cbind(time , time_cut))
reflexity_res <- list()
for (i in 1:13) {
ref_time <- time[reflexity$time_cut==i]
ref_time <- ref_time - ref_time[1]
ref_res <- nlminb(c(1,1,1) , log_likelihood ,event= ref_time )
reflexity_res[[i]] <- ref_res
}
## Warning messages:
## 1: In log(lambda) : \u4ea7\u751f\u4e86NaNs
## 2: In nlminb(c(1, 1, 1), log_likelihood, event = ref_time) :
## NA/NaN function evaluation
## 3: In log(lambda) : \u4ea7\u751f\u4e86NaNs
## 4: In nlminb(c(1, 1, 1), log_likelihood, event = ref_time) :
## NA/NaN function evaluation
## 5: In log(lambda) : \u4ea7\u751f\u4e86NaNs
## 6: In nlminb(c(1, 1, 1), log_likelihood, event = ref_time) :
## NA/NaN function evaluation
mu_vec <- c()
alpha_vec <- c()
beta_vec <- c()
for (i in 1:13) {
mu_vec <- c(mu_vec , reflexity_res[[i]]$par[1])
alpha_vec <- c(alpha_vec , reflexity_res[[i]]$par[2])
beta_vec <- c(beta_vec , reflexity_res[[i]]$par[3])
}
time_vec <- seq(market_order$time[1]-0.01 , market_order$time[nrow(market_order)]+0.01 , length.out=14)
time_vec <- as.POSIXct(time_vec,origin="1970-01-01",tz="America/Chicago")
par(mfrow=c(2,1))
plot(time_vec[1:(length(time_vec)-1)],mu_vec , col="blue" , type="b" , xlab="time" , ylab="mu" , main="background intensity in different periods")
plot(time_vec[1:(length(time_vec)-1)] , col="red" , type="b",alpha_vec/beta_vec , xlab="time" , ylab="alpha/beta",main = "reflexity in different periods" )
我們把背景強度和 reflexity 分別畫出來,可以看到背景強度形成了一個碗狀,說明開盤和收盤時的事件的背景強度較大。而 reflexity 則在各個 時間段基本一致,基本圍繞 0.4 波動。
2.3 考慮訂單數量
前面我們把訂單視作同質進行分析 ,但是很明顯量大的訂單對市場的衝擊更大,我們應該 把訂單的數量考慮進去。
首先我們看一下整個時間段的訂單強度:
plot(time , vol , type="l" , ylab="volume" , xlab="time" , main="market order intensity")
然後我們可以開始嘗試建模,將量的因素考慮進去:
其中 nj 代表第 j 個事件的數量。
log_likelihood_volume <- function(params , event , vol) {
mu = params[1]
alpha = params[2]
beta = params[3]
n = length(event)
t_n = event[n]
kernel_sum <- numeric(n)
for (i in 2:n) {
kernel_sum[i] = (kernel_sum[i-1]+alpha*vol[i-1]) * exp(-beta*(event[i] - event[i-1]))
}
lambda <- kernel_sum + mu
L = sum( log(lambda) ) - mu * t_n - alpha/beta*sum(vol) + alpha/beta*sum(vol*exp(-beta*(t_n-event)))
#print(L)
-L
}
nlminb(c(1,1,1) , log_likelihood_volume ,event= time , vol= vol )
## Warning in log(lambda): NaNs produced
## Warning in nlminb(c(1, 1, 1), log_likelihood_volume, event = time, vol =
## vol): NA/NaN function evaluation
## Warning in log(lambda): NaNs produced
## Warning in nlminb(c(1, 1, 1), log_likelihood_volume, event = time, vol =
## vol): NA/NaN function evaluation
## Warning in log(lambda): NaNs produced
## Warning in nlminb(c(1, 1, 1), log_likelihood_volume, event = time, vol =
## vol): NA/NaN function evaluation
## $par
## [1] 1.557608 7.106736 293.679848
##
## $objective
## [1] -82261.69
##
## $convergence
## [1] 0
##
## $iterations
## [1] 44
##
## $evaluations
## function gradient
## 56 150
##
## $message
## [1] "relative convergence (4)"
2.4 訂單數量的冪指數
前面我們假設訂單量的影響是線性的,可真實是這樣的嗎,我們嘗試在訂單數量上加入一個冪指數。
那麼強度的表示式變為
log_likelihood_volume_exponent <- function(params , event , vol) {
mu = params[1]
alpha = params[2]
beta = params[3]
k = params[4]
n = length(event)
t_n = event[n]
kernel_sum <- numeric(n)
vol <- vol^k
for (i in 2:n) {
kernel_sum[i] = (kernel_sum[i-1]+alpha*vol[i-1]) * exp(-beta*(event[i] - event[i-1]))
}
lambda <- kernel_sum + mu
L = sum( log(lambda) ) - mu * t_n - alpha/beta*sum(vol) + alpha/beta*sum(vol*exp(-beta*(t_n-event)))
-L
}
nlminb(c(1,1,1,1) , log_likelihood_volume_exponent ,event= time , vol= vol)
## $par
## [1] 1.5214343 42.1613593 321.6189710 0.5287265
##
## $objective
## [1] -86579.32
##
## $convergence
## [1] 0
##
## $iterations
## [1] 51
##
## $evaluations
## function gradient
## 67 231
##
## $message
## [1] "relative convergence (4)"
從引數我們可以看到k的值大約是 0.5 , 說明訂單的影響大約是數量的根號,並不是線性增長的。 這是非常有趣的一個現象 , 說明訂單量的衝擊是邊際遞減的。
三、 總結
在前面我們對市價單的動力學進行建模 , 我們看到了一些有趣的現象, 例如日內交易背景強度的變化;訂單數量影響的冪指數小於1。 這些都可以做進一步地挖掘,可以讓我們更加深入地理解市場的動力學。