一、订单簿基础:限价单与市价单、买卖盘口、深度图、订单簿快照与增量更新
各位同学,咱们今天聊点实在的。订单簿这东西,说白了就是交易所用来撮合买卖双方的那张「记账本」。我做了这么多年量化,见过不少人一上来就搞什么深度学习预测价格,结果连订单簿怎么更新都没搞清楚——嗯,这坑我踩过,所以今天咱们先把地基打牢。
1.1 限价单 vs 市价单:两种最基础的订单类型
先问大家一个问题:你想买比特币,是直接按市场价买,还是挂个低价等着?这两种操作,对应的就是市价单和限价单。
- 市价单(Market Order):不指定价格,直接吃掉对手盘上最好的挂单。我习惯叫它「梭哈单」——成交快,但价格不确定。行情剧烈波动时,你可能买在尖尖上。
- 限价单(Limit Order):指定一个价格,挂在那里等别人来吃。成交慢,但价格可控。我在做做市策略时,90%的订单都是限价单。
核心区别:市价单提供「流动性消耗」,限价单提供「流动性供给」。交易所喜欢限价单,因为深度好;散户喜欢市价单,因为省心。
举个例子。假设当前盘口是这样的:
| 卖五 | 100.50 | 200股 |
|---|---|---|
| 卖四 | 100.40 | 150股 |
| 卖三 | 100.30 | 300股 |
| 卖二 | 100.20 | 100股 |
| 卖一 | 100.10 | 500股 |
| 买一 | 100.00 | 400股 |
| 买二 | 99.90 | 250股 |
| 买三 | 99.80 | 600股 |
| 买四 | 99.70 | 100股 |
| 买五 | 99.60 | 300股 |
你下了一个买入市价单,想买800股。系统会先吃掉卖一的500股(100.10),再吃掉卖二的100股(100.20),再吃掉卖三的200股(100.30)——成交均价是100.1625。你看,价格滑出去了。
如果你挂一个限价买单,价格设在100.00,那就只能等价格跌下来才能成交。我曾经在2017年做ETH交易时,挂了个限价单差了0.1美元没成交,结果行情直接起飞——嗯,这就是限价单的痛。
1.2 买卖盘口:订单簿的「第一道防线」
买卖盘口,就是订单簿上最靠前的几档价格。买一、卖一、买二、卖二……这些数据是高频交易的核心输入。
我个人习惯把盘口数据分成三个层次来看:
- 第一层(Top of Book):买一和卖一的价格、数量。这是最直接的「当前市场价」。
- 第二层(Depth 2-5):买二到买五、卖二到卖五。用来判断短期支撑和压力。
- 第三层(Full Depth):整个订单簿。做市商和机构常用,散户一般看不到。
实战技巧:别只看买一卖一。我见过有人根据买一卖一价差做套利,结果忽略了买二到买五的挂单量,一进去就被砸穿了。盘口深度才是真正的「护城河」。
1.3 深度图:把订单簿画出来
深度图(Depth Chart)就是把订单簿可视化。横轴是价格,纵轴是累计挂单量。买盘从左到右递增,卖盘从右到左递减。两条线交叉的地方,就是当前市场价格。
为什么要看深度图?因为数字太抽象了。你盯着买一100.00有400股,卖一100.10有500股,很难直观感受到「如果来个大单会怎样」。但深度图一眼就能看出来——价格每变动0.1元,需要吃掉多少流动性。
我给大家画个简单的深度图结构:
这张图里,红色是买盘,绿色是卖盘。两条线越陡,说明深度越好,价格不容易被推动。反过来,如果某条线很平缓,说明那个价位附近挂单很少——这就是所谓的「薄区域」,大资金一进来价格就飞了。
注意:深度图是静态快照,不代表下一秒的深度。我曾经在回测时用历史深度图做模拟,结果实盘时发现深度完全不一样——因为市场在变,订单在撤。深度图只能给你一个「当前时刻」的参考。
1.4 订单簿快照与增量更新
这是高频交易里最核心的数据处理方式。交易所不会每秒给你发整个订单簿——数据量太大了。它们用的是「快照+增量」的模式。
快照(Snapshot):某个时间点订单簿的完整状态。比如每天开盘时发一次,或者每10秒发一次。
增量更新(Incremental Update):每次有订单成交、挂单、撤单时,只发变化的部分。比如「卖一价格从100.10变成100.15,数量从500变成300」。
我给大家看一段伪代码,理解一下这个逻辑:
# 初始化订单簿
order_book = get_snapshot(exchange, symbol)
# 实时处理增量更新
while True:
update = receive_update(exchange, symbol)
if update.type == 'NEW':
# 新挂单
order_book.add(update.price, update.side, update.quantity)
elif update.type == 'CANCEL':
# 撤单
order_book.remove(update.order_id)
elif update.type == 'TRADE':
# 成交
order_book.reduce(update.price, update.side, update.quantity)
# 更新盘口
top_bid = order_book.get_top_bid()
top_ask = order_book.get_top_ask()
spread = top_ask.price - top_bid.price
print(f"买一: {top_bid.price} ({top_bid.quantity}) | 卖一: {top_ask.price} ({top_ask.quantity}) | 价差: {spread}")
这段代码虽然简单,但包含了订单簿维护的核心逻辑。我在做高频策略时,最头疼的就是增量更新的时序问题——如果增量更新来晚了,或者顺序乱了,订单簿就会「漂移」。曾经有一次,我因为没处理好增量更新的顺序,导致策略在实盘时算错了盘口深度,白白亏了2个BP——嗯,从那以后我加了个序列号校验。
关键点:增量更新必须保证「因果一致性」。如果先收到撤单再收到挂单,那没问题。但如果先收到挂单再收到撤单,而撤单的订单ID是之前已经存在的——那就要小心了,可能是个「幽灵订单」。
1.5 实战中的避坑指南
最后,分享几个我踩过的坑:
- 别信「全量快照」:交易所发的快照也可能有延迟。我建议每次收到快照后,先跟本地维护的订单簿做一次交叉验证。
- 注意价格精度:不同交易所的价格精度不一样。有的支持小数点后8位,有的只支持2位。精度不对,订单簿就乱了。
- 盘口数据要「去重」:同一个价格可能有多个订单,但盘口只显示总量。如果你要分析订单粒度,得用Level 3数据。
- 小心「冰山订单」:有些大单只显示一部分,实际挂单量远大于显示量。只看盘口会被误导。
好了,订单簿的基础就讲到这里。记住一句话:订单簿是市场的「骨架」,盘口是「肌肉」,增量更新是「血液」。这三者搞明白了,后面的高频信号提取才有意义。