【在公众号对话框,回复 AFML2 可下载数据】
本文是 AFML 系列的第二篇
从 Tick 到 Bar
在做量化时,经常会用到下面格式的金融数据。
这条数据 (后文称作 bar) 包含 6 个属性:
日期时间 (date_time) 是 2013 年 9 月 1 日 19 时 32 分 23 秒 387 毫秒
起始价 (open) 是 1640.25
最高价 (high) 是 1642.00
最低价 (close) 是 1639.00
结束价 (high) 是 1642.00
成交量 (volume) 为 28031
注意我并有把 open 和 close 翻译成开盘价和收盘价,因为这条数据并不是按日来收集的,而它对应的时间精确到 387 毫秒。
另外为什么在一个时点上有四种不同的价格,即市场常见的 OHLC? (每个字母代表 open, high, low, close 四个单词的首个字母)。原因是 OHLC 数据是在一段时间内 (上面 09/01/2013 19:32:23.387 是这段时间的终点) 收集很多 tick 数据的价格而决定的它们的 open, high, low, close,这段时间可以是
一天
一小时
一分钟
一秒
包含 1000 笔交易的那段时间
包含成交 100 个合约的那段时间
包含成交 10000 美元的那段时间
收集 tick 数据而生成某些统计量的操作叫抽样 (sample),这些统计量可以是这些 tick 数据的
起始值、最大值、最小值、终止值 (OHLC)
简单平均值 (下面要介绍的 TWAP)
成交量加权平均值 (下面要介绍的 VWAP)
其实本帖讲的内容就是简单的抽样,从大量「tick 级别」的高频数据,选出有代表性「bar 类型」的样本。
但本帖的内容很重要,很多人都迷恋复杂的算法,但往往忽略了数据的质量,有些时候并不是好的算法赢,而是好的数据赢。
本帖的目录如下:
目录第一章 - Tick 和 Bar
1.1 Tick 数据
1.2 Bar 数据
第二章 - 标准 Bar
2.1 比特币永续掉期高频数据
2.2 等时抽样之 Time Bar
2.3 等笔抽样之 Tick Bar
2.4 等量抽样之 Volume Bar
2.5 等额抽样之 Dollar Bar
第三章 - 信息驱动 Bar
3.1 S&P 500 期货高频数据
3.2 Imbalance Bar
3.3 Runs Bar
总结
1.1
Tick 数据
Tick 不是下左图中的水滴答的声音,而是下右图中某种金融产品交易时的逐笔数据。
Tick 数据也是交易所对定单薄 (order book) 中进行增加、删除、更新和成交四个操作产生的数据。换句话说,只要在定单薄中买价、买量、卖价和卖量发生变化,那么就产生一个 tick。下图展示了某加密货币的 tick 数据。
国内交易所发送是切片信息,还不是真正意义的 tick 信息。以切片间隔时间为 500 毫秒举例,一个切片相当于一份快照,然而这 500 毫秒内的任何变化,你是没法看到的。下图的立方体可想象成 tick 信息,红色立方体是快照每 500 毫秒捕捉到的,而深青色立方体是遗漏掉的。
以切片间隔时间为 500 毫秒,含三档行情 (三买单三卖单) 的定单薄来举例。
解释一下:
在 10 时 31 分 08 秒 200 毫秒的时候,有人以 160 的买价卖出 200 股,最新成交价为 160,总成交量为 200 股,但此时因为未到切片时间 (500 毫秒),所以不会推送数据出来。
在 10 时 31 分 08 秒 400 毫秒的时候,有人想以 160.5 的价格卖 200 股,信息添加到限价定单薄上,此时仍未到切片时间,仍不会推送数据。
在 10 时 31 分 08 秒 500 毫秒的时候,有人以 160.5 的买价卖出 100 股,最新成交价为 160.5,总成交量为 300 股,此时交易所生成一份快照,并推送出来,这就是我们能够接收到的所谓的 tick 数据。实际上我们丢失了不少信息,不如我们根本不知道在 160 的时候也有成交。
按上图流程所示,如果 160 是当日的最低价,则可能会出现因为信息丢失而无法获得,所以国内交易所都会单独推送一份当日最高最低价以弥补。
1.2
Bar 数据
为了高频的 tick 数据从中提取有价值的信息,并以合适的形式存储它们。这种数据储存形式叫做 bar。这里的 bar 指的不是下左图中的酒吧,而是下右图里的一个单元。
将右图的单元放大得到两种类型的 bar (绿色空心代表价格上升的 bar,红色实心代表价格下降的 bar):
我在〖Python 系列〗里最喜欢说的一句就是「万物皆对象」,这里 bar 也不例外,也是个对象,它里面的属性有最高价 (high)、最低价 (low)、开盘价 (open)、收盘价 (close) 和成交量 (volume)。之后我们遇到的 bar 会有更多属性,比如时间戳 (timestamp)、代号 (symbol)、ID 等等。
搞量化时总不能把上面的 bar 图形当成数据格式储存吧,想想 DataFrame,把 bar 里每一条属性当成 Column,那么每一条记录 (observation) 或一个样例 (instance) 就是一个 bar,而 DataFrame 就是存储多个 bar 的数据结构 (再回到开头的那幅图)。
在后面两章,我们介绍如何构建
文献中常见的标准 bar
实践中复杂的信息驱动 bar
构建标准 bar 通过标准抽样 (regular sampling),将非均匀序列的「原始数据」转化为均匀序列的「加工数据」。
2.1
比特币永续掉期高频数据
采用的是 BitMEX 交易所里交易的比特币/美元永续掉期 (XBTUSD perpetual swap)。XBTUSD 永续掉期合约则没有到期日,可以一直持仓。
以 2019 年 4 月 19 日这一天 XBTUSD 永续掉期的交易数据为例,其原始数据记录每个有交易的时点下的信息。注意每个 tick 的时间戳 (time stamp) 的时间值是非均匀的,看下图红色框里的精确到秒后 6 位数字的三个时间,分别是 8.318873, 8.367122 和 8.449684。
接下来「读取-概览-处理-可视化」数据。
读取四天的高频数据,获取 symbol 为XBTUSD 的相关数据。发现有 1434823 条tick 数据,每条数据有 10 个特征。
重要的五栏是
side:买卖方向
price:价格
tickDirection:每笔的价格走向。
minusTick 是价格向下
zeroMinusTick 都是价格不变但前一个 tick 价格向下
plusTick 是价格向上
zeroPlusTick 都是价格不变但前一个 tick 价格向上
homeNotional:合约数,即 volume
foerignNotional:成交额,以美元为单位
由于 DataFrame 的行标签是 XBTUSD 并不是从 0 开始的 (从 csv 读取的原数据中含有好几种加密货币的永续掉期),因此我们用 reset_index() 来重新给出行标签。
原来的行标签变成了列标签 index,其实上次信息没什么用,用 drop() 函数删除该列。
最后发现时间戳太长了,后面多了 3 个零根本用不到,而且中间还多了一个 ‘D’ 字符串,用 map() 函数将其转换成「年-月-日 时:分:秒.毫秒」标准格式。