专栏名称: quantOS
quantOS 量化开源系统的一站式解决方案
目录
相关文章推荐
51好读  ›  专栏  ›  quantOS

数字货币量化交易基础(3)

quantOS  · 公众号  ·  · 2018-04-11 08:59

正文

请到「今天看啥」查看全文


在上篇文章里,提到了高频交易需要仔细研究订单队列(OrderBook),本节介绍订单队列的基本知识。

本文包括如下几个部分:

  • 什么是订单队列?

  • 如何构建订单队列?

  • 队列深度图是怎么回事?

  • 如何用python画自己的队列深度图?

什么是订单队列?

订单队列就是在交易所排队的未成交订单的信息。比如在某个瞬间,GDAX交易所BTC-USD的订单队列如下:

  1. 6744.680000 0.100000 sell

  2. 6744.000000 0.001000 sell

  3. 6743.550000 1.400000 sell

  4. 6743.540000 0.100000 sell

  5. 6743.480000 0.002000 sell

  6. 6743.220000 0.001000 sell

  7. 6743.010000 1.000000 sell

  8. 6742.810000 2.500000 sell

  9. 6742.250000 3.502058 sell

  10. 6741.020000 13.092218 sell

  11. ---------------------------

  12. 6741.010000 0.331101 buy

  13. 6741.000000 0.001000 buy

  14. 6740.990000 0.005558 buy

  15. 6740.460000 0.001000 buy

  16. 6740.340000 0.100000 buy

  17. 6740.170000 0.001000 buy

  18. 6740.130000 0.010571 buy

  19. 6740.000000 0.241145 buy

  20. 6739.990000 0.348368 buy

  21. 6739.880000 0.003147 buy

交易所在发布订单队列时,相同价位的订单数量会合并计算。

如何构建订单队列?

在我们做高频交易时,需要及时更新订单队列,计算高频信号。那如何构建自己的订单队列呢?

各个交易所提供的技术解决方案雷同,都是用推送的方式,将订单簿的更新信息推送到用户。

以GDAX交易所为例子,它会通过WebSocket接口中的level2频道,推送订单簿的变化信息。API原文如下:

  • The easiest way to keep a snapshot of the order book is to use the level2 channel. It guarantees delivery of all updates, which reduce a lot of the overhead required when consuming the full channel.

  • When subscribing to the channel it will send a message with the type snapshot and the corresponding product_id. bids and asks are arrays of [price, size] tuples and represent the entire order book.

  • Subsequent updates will have the type l2update. The changes property of l2updates is an array with [side, price, size] tuples. Please note that size is the updated size at that price level, not a delta. A size of "0" indicates the price level can be removed.

也就是通过三步:

  1. 订阅level2频道。

  2. 接收当前全量的订单簿。

  3. 接收订单簿的更新。

用户可以在内存中根据交易所返回的信息,构建最新的订单簿。python代码如下:

  1. from sortedcontainers import SortedDict

  2. import matplotlib.pyplot as plt

  3. class Order():

  4.    def __init__(self, price, size, action):

  5.        self.price  = price

  6.        self.size   = size

  7.        self.action = action

  8. class OrderBook():

  9.    def __init__(self):

  10.        self.bids = SortedDict()

  11.        self.asks = SortedDict()

  12.    # process orderbook update

  13.    def process(self, data):

  14.        for k, v in data.items():

  15.            if v.action == 'buy':

  16.                self .bids[k] = v

  17.                if v.size == 0.0:

  18.                    self.bids.pop(k)

  19.            elif v.action == 'sell':

  20.                self.asks[k] = v

  21.                if v.size == 0.0:

  22.                    self.asks.pop(k)

  23.    def show(self, depth):

  24.        for k in (self.asks.keys())[depth::-1]:

  25.            print('%.6f %.6f %s' % (k, self.asks[k].size, self.asks[k].action))

  26.        for k in (self.bids.keys())[-1:-depth:-1]:

  27.            print('%.6f %.6f %s' % (k, self.bids[k].size, self.bids[k].action))

通过websocket接收推送数据

  1. from websocket import create_connection

  2. import json

  3. if __name__ == '__main__':

  4.    while(1):

  5.        try:

  6.            ws = create_connection("wss://ws-feed.gdax.com")

  7.            break

  8.        except:

  9.            print('connect ws error,retry...')

  10.            time.sleep(5)

  11.    subscribeStr="""{"type": "subscribe","product_ids": ["BTC-USD"], "channels": [{"name":"level2", "product_ids":["BTC-USD"]}]}"""

  12.    ws.send(subscribeStr)

  13.    orderbook = OrderBook()

  14.    i = 0

  15.    while(1):

  16.        recvData=ws.recv()

  17.        result = json.loads(recvData)

  18.        res_type = result['type']

  19.        data = {}

  20.        if res_type == 'snapshot':

  21.            bids = result['bids']

  22.            for value in bids:

  23.                price = float(value[0])

  24.                size  = float(value[1])

  25.                data[price] = Order(price, size, 'buy')

  26.            asks = result['asks']

  27.            for value in asks:

  28.                price = float(value[0])

  29.                size  = float(value[1])

  30.                data[price] = Order(price, size, 'sell')

  31.        if res_type == 'l2update':

  32.            changes = result['changes']

  33.            for value in changes:

  34.                side  = value[0]

  35.                price = float(value[1])

  36.                size  = float(value[2])

  37.                data[price] = Order(price, size, side)

  38.        orderbook.process(data)

  39.        # display top 10 orders

  40.        orderbook.show(10)

队列深度图是怎么回事?

这是一幅GDAX上的BTC-USD队列深度图,用来描述买卖订单的平衡情况。其中:

  1. mid market price = (best bid price + best ask price) / 2

  2. X轴表示价格,Y轴表示累计的订单大小。即表示以此价格可以获得(买到或者卖掉)的最大数量。

队列深度图可以作为描述市场力量平衡的一个指标,但不能完全按照队列深度图操作,因为:

  1. 订单还有可能被撤销

  2. 离mid market price越远的订单,真实性越低。有可能是某些人故意放进来干扰的。

如何用python画自己的队列深度图?

队列深度图是一个阶梯图,直接上python代码:

  1. from collections import OrderedDict

  2. from sortedcontainers import SortedDict

  3. import matplotlib.pyplot as plt

  4. class OrderBook():

  5.    def __init__(self):

  6.        self.bids = SortedDict()

  7.        self.asks = SortedDict()

  8.    def process(self, data):

  9.         for k, v in data.items():

  10.            if v.action == 'buy':

  11.                self.bids[k] = v

  12.                if v.size == 0.0:

  13.                    self.bids.pop(k)

  14.            elif v.action == 'sell':

  15.                self.asks[k] = v

  16.                if v.size == 0.0:

  17.                    self.asks.pop(k)

  18.    def show(self, depth):

  19.        for k in (self.asks.keys())[depth::-1]:

  20.            print('%.6f %.6f %s' % (k, self.asks[k].size, self.asks[k].action))

  21.        for k in (self.bids.keys())[-1:-depth:-1]:

  22.            print('%.6f %.6f %s' % (k, self.bids[k].size, self.bids[k].action))

  23.    def draw_depth(self, width):

  24.        bid = self.bids.keys()[-1]

  25.        ask = self.asks.keys()[0]

  26.        mid = (bid+ask) / 2.0

  27.        print('mid=%.6f' % (mid))

  28.        steps = width * 10

  29.        ask_x = [mid + float(i) * 0.1 for i in range(steps)]

  30.        bid_x = [mid - float(i) * 0.1 for i in range(steps)]

  31.        cum_size = 0.0

  32.        cum_data = OrderedDict()

  33.        for k, v in self.asks.items():

  34.            price = k

  35.            size  = v.size

  36.            cum_size = cum_size + size

  37.            cum_data[price] = cum_size

  38.        ask_y = []

  39.        start = 0

  40.        for k, v in cum_data.items():

  41.            price = k

  42.            size  = v

  43.            if start >= len(ask_x):

  44.                break

  45.            for i in range(start, len(ask_x)):

  46.                cum_value = 0.0

  47.                if ask_x[i] <= price:

  48.                    cum_value = size

  49.                    ask_y.append(cum_value)

  50.                else:

  51.                    start = i

  52.                    break

  53.            if len(ask_y) >= len(ask_x):

  54.                 break

  55.        cum_size = 0.0

  56.        cum_data = OrderedDict()

  57.        for k in reversed(self.bids):

  58.            price = k

  59.            size = self.bids[k].size

  60.            cum_size = cum_size + size

  61.            cum_data[price] = cum_size

  62.        bid_y = []

  63.        start = 0

  64.        for k, v in cum_data.items():

  65.            price = k

  66.            size  = v

  67.            if start >= len(bid_x):

  68.                break

  69.            for i in range( start, len(bid_x)):

  70.                cum_value = 0.0

  71.                if bid_x[i] >= price:

  72.                    cum_value = size

  73.                    bid_y.append(cum_value)

  74.                else:

  75.                    start = i

  76.                    break

  77.            if len(bid_y) >= len(bid_x):

  78.                break;

  79.        bid_x.reverse()

  80.        bid_y.reverse()

  81.        bid_x.extend(ask_x)

  82.        bid_y.extend(ask_y)

  83.        fig, ax = plt.subplots(figsize=(16,6))

  84.        ax.vlines(mid, 0, 600, color='red', linestyle='--')

  85.        ax.hlines(0, mid-width, mid+width, color='blue', linestyle='--')

  86.        ax.step(bid_x, bid_y)

  87.        plt.show()

  88. # call function

  89. orderbook.draw_depth(100)        

输出结果是这个样子的:








请到「今天看啥」查看全文


推荐文章
21世纪经济报道  ·  2017,谁是下一只“黑天鹅”?
8 年前
科学解码  ·  磁铁要这样玩才有趣 不然就是瞎玩
8 年前
教你看穿男人的心  ·  拥有这4种气质的女人最迷人!
8 年前
美味书单  ·  好欺负的女人都长这样
7 年前