一、订单簿基础:限价单与市价单、买卖盘口、深度图解读、订单簿数据结构
做量化交易这些年,我见过太多人一上来就研究各种复杂策略,结果连订单簿都没搞明白。说实话,订单簿就是市场的「心电图」,看不懂它,你就是在闭着眼睛交易。
这一章,咱们把订单簿的底裤扒干净。从最基础的单子类型,到盘口数据怎么读,再到深度图背后的博弈逻辑,最后我会给你看订单簿在内存里到底长什么样。
1.1 限价单 vs 市价单:两种「下单姿势」
先问个问题:你想买比特币,现在卖一价是30000 USDT。你该怎么办?
两种选择:
- 市价单:不管价格,直接吃掉卖一的所有单子。成交价就是30000,但可能滑到30001、30002。
- 限价单:你挂一个29990的买单,等着别人来砸给你。成交价固定,但可能等很久,甚至永远成交不了。
我个人习惯把市价单叫「急性子单」,限价单叫「守株待兔单」。你想想看,做高频策略时,市价单是抢跑用的;做做市策略时,限价单才是你的武器。
核心区别一句话:市价单保证成交,不保证价格;限价单保证价格,不保证成交。
我在项目中遇到过一件事:有个学员用市价单做套利,结果遇到流动性枯竭,一笔单子滑了0.3%。嗯,0.3%在套利里基本等于白干。从那以后,我建议所有做套利的朋友,至少用「限价单+冰山委托」的组合。
1.2 买卖盘口:订单簿的「骨架」
打开任何一个交易所的深度图,你会看到左右两列数字。左边是买盘(Bid),右边是卖盘(Ask)。
举个例子,BTC/USDT的盘口可能是这样的:
| 买价 (Bid) | 买量 | 卖价 (Ask) | 卖量 |
|---|---|---|---|
| 30000 | 1.5 BTC | 30005 | 2.0 BTC |
| 29995 | 3.0 BTC | 30010 | 1.8 BTC |
| 29990 | 5.0 BTC | 30015 | 4.0 BTC |
这里有个关键概念叫「买卖价差」(Spread)。就是卖一价减去买一价,30005 - 30000 = 5 USDT。价差越小,说明市场流动性越好。我记得2017年比特币刚火的时候,价差经常几十美元,现在主流交易所基本稳定在1-2美元。
避坑指南:我曾经以为价差越小越好,直到有一次在某个小交易所做套利,价差只有0.1 USDT,但一成交才发现,手续费吃掉了一半利润。所以看价差时,一定要把手续费算进去。
1.3 深度图解读:订单簿的「肌肉」
深度图就是把所有买单和卖单按价格累加起来,画成两条曲线。左边是买盘累积,右边是卖盘累积。
怎么看深度图?我教你三个要点:
- 看斜率:曲线越陡,说明该价格附近堆积的单子越多,支撑或阻力越强。
- 看缺口:如果某个价格区间突然没有单子,那就是「流动性真空区」。价格一旦穿过这里,会像自由落体一样。
- 看深度:比如你想买100个BTC,看深度图就知道会不会把价格打穿。
为什么会这样?说白了,深度图就是市场参与者的「心理防线」。每个挂单背后都是一个活生生的人,或者一个算法。你想想看,当价格逼近某个密集挂单区时,挂单的人会不会撤单?这就是博弈。
下面是我手绘的一张订单簿结构图,帮你理清思路:
1.4 订单簿数据结构:内存里的「战场」
好了,现在咱们聊聊代码层面的事。订单簿在内存里到底怎么存的?
最经典的数据结构是「价格-数量映射表」,说白了就是一个有序字典。买盘按价格降序排列,卖盘按价格升序排列。
我一般用Python的sortedcontainers库来实现,或者直接用dict加list手动排序。给你看个简化版:
class OrderBook:
def __init__(self):
self.bids = {} # 买盘: {价格: 数量}
self.asks = {} # 卖盘: {价格: 数量}
self.bid_prices = [] # 排序后的买价列表
self.ask_prices = [] # 排序后的卖价列表
def update(self, side, price, size):
"""更新订单簿"""
if side == 'bid':
if size == 0:
# 数量为0表示撤单
self.bids.pop(price, None)
else:
self.bids[price] = size
# 重新排序
self.bid_prices = sorted(self.bids.keys(), reverse=True)
else:
if size == 0:
self.asks.pop(price, None)
else:
self.asks[price] = size
self.ask_prices = sorted(self.asks.keys())
def get_top_of_book(self):
"""获取最优买卖价"""
best_bid = self.bid_prices[0] if self.bid_prices else None
best_ask = self.ask_prices[0] if self.ask_prices else None
return best_bid, best_ask
注意:实际生产环境中,订单簿更新频率极高(毫秒级)。我曾经用纯Python实现,结果每秒处理5000次更新就卡死了。后来改用C++或者用Redis的有序集合(ZSET),才扛住高频场景。
这里有个细节:交易所推送的订单簿数据,通常有两种格式:
- 增量更新:只推送变化的部分(推荐,带宽小)
- 全量快照:每隔一段时间推送整个订单簿(用于校验)
我个人习惯的做法是:维护一个本地订单簿,用增量更新实时修改,每隔10秒用全量快照做一次「对账」。嗯,这招帮我避免过好几次数据错乱的问题。
1.5 订单簿不平衡度:量化交易的「圣杯」?
终于聊到核心了。订单簿不平衡度(Order Book Imbalance),说白了就是看买盘和卖盘谁更强。
最简单的公式:
imbalance = (bid_volume - ask_volume) / (bid_volume + ask_volume)
这个值在-1到1之间。正数表示买盘强,负数表示卖盘强。但说实话,只看总量太粗糙了。我一般会看不同价格深度的不平衡:
- 近端不平衡:只看买一卖一附近(反应短期博弈)
- 远端不平衡:看买五卖五甚至更深(反应中长期意图)
举个例子,如果近端买盘强但远端卖盘更强,说明什么?说明有人在近端拉高诱多,但远端已经挂好了卖单准备砸盘。这种「背离」信号,我用来做反转策略效果不错。
我的经验:不平衡度不是万能的。2019年我靠这个指标赚了不少,但2020年3月12日那天,市场暴跌时订单簿瞬间失效——因为所有人都撤单了,流动性直接消失。所以记住:任何指标都要结合市场环境看。
好了,这一章的内容就这些。订单簿是量化交易的「地基」,地基不稳,上面盖什么楼都得塌。下一章咱们会深入讲不平衡度的各种变体,以及怎么用它构建实盘策略。
公众号:蓝海资料掘金营,微信deep3321