第1章:订单簿微观结构
做高频做市,说白了就是跟订单簿打交道。你每天盯着的那个不断跳动的买卖挂单列表,就是你的战场。我刚开始接触这个领域时,觉得订单簿不就是个价格队列嘛,有什么好研究的?直到有一次,我因为忽略了订单簿的微观结构,在毫秒级别上亏了一大笔——嗯,从那以后我再也不敢小看它了。
1.1 限价订单簿:L2与L3
先说说最基础的概念。限价订单簿,英文叫Limit Order Book,简称LOB。它是交易所用来记录所有未成交限价订单的数据结构。
L2数据,也就是市场深度数据,展示的是每个价格档位的聚合挂单量。比如买一价100.00元挂了1000股,买二价99.99元挂了2000股,卖一价100.01元挂了1500股——这就是典型的L2快照。
L3数据则更细,它展示的是每一笔独立的订单,而不是聚合后的总量。L3能看到每个价格档位下有多少个订单,每个订单是谁挂的、什么时候挂的、挂了多少。
关键区别:L2告诉你「这个价格有多少量」,L3告诉你「这个量是怎么组成的」。做高频做市,L3的价值在于你能分析订单的拆分策略和撤单行为。
我个人习惯,在开发做市策略时,L3数据是必须的。为什么?因为L2的聚合数据会掩盖很多细节。举个例子,卖一价挂了5000股,这5000股可能是一个大单,也可能是50个100股的小单。这两种情况对价格的冲击完全不同。大单可能是机构在出货,小单可能是散户在试水。你想想看,如果只看L2,你根本分不清。
1.2 订单簿的动态变化
订单簿不是静止的。它每时每刻都在变化。主要的事件类型就四种:
- 新订单进入:有人挂了新的限价单
- 订单成交:限价单与对手方订单匹配
- 订单撤单:挂单的人取消了订单
- 订单修改:修改价格或数量(有些交易所支持)
我在项目中遇到过一个问题:某个品种的订单簿更新频率极高,每秒上千次。如果用轮询方式去拉取数据,延迟根本扛不住。后来我改用WebSocket订阅增量更新,只接收变化的部分,再本地维护一个全量订单簿。这样延迟降到了微秒级别。
实战技巧:维护本地订单簿时,一定要处理好事件顺序。交易所发来的增量更新可能乱序,你需要用序列号或时间戳来排序。我曾经因为没处理好乱序问题,导致本地订单簿和交易所对不上,策略直接崩了。
下面是一个简单的订单簿维护逻辑,用Python示意:
class OrderBook:
def __init__(self):
self.bids = {} # 价格 -> 总量
self.asks = {}
def apply_snapshot(self, snapshot):
# 用全量快照初始化
self.bids = {level['price']: level['size']
for level in snapshot['bids']}
self.asks = {level['price']: level['size']
for level in snapshot['asks']}
def apply_update(self, update):
# 处理增量更新
for side in ['bids', 'asks']:
for level in update[side]:
price = level['price']
size = level['size']
if size == 0:
# 数量为0表示该档位被删除
getattr(self, side).pop(price, None)
else:
getattr(self, side)[price] = size
1.3 买卖价差与市场深度
买卖价差,就是卖一价减去买一价。这个指标直接反映了市场的流动性成本。价差越小,说明流动性越好,你进出场的成本越低。
市场深度,则是指某个价格附近能成交的量。通常看的是买一到买五、卖一到卖五的总量。深度越大,说明市场能吸收大额订单而不产生太大价格冲击。
| 指标 | 定义 | 做市中的意义 |
|---|---|---|
| 买卖价差 | 卖一价 - 买一价 | 你的潜在利润空间 |
| 市场深度 | 各档位挂单总量 | 你能安全挂单的量级 |
| 价差波动率 | 价差的变化幅度 | 判断市场是否异常 |
做高频做市,价差和深度是你每天都要盯的。我记得有一次,某个品种的价差突然从0.01元扩大到0.05元,我第一反应是撤单。果然,几秒后价格剧烈波动,如果我还挂着单,肯定被吃掉。说白了,价差异常扩大往往是市场出现异动的先兆。
1.4 订单簿不平衡指标
订单簿不平衡,英文叫Order Book Imbalance,简称OBI。它衡量的是买单总量和卖单总量的差异。
最简单的计算公式:
OBI = (bid_volume - ask_volume) / (bid_volume + ask_volume)
OBI的取值范围在-1到1之间。正值表示买单力量更强,负值表示卖单力量更强。绝对值越大,不平衡程度越高。
但实际应用中,我不会只用这个简单的公式。为什么?因为不同价格档位的订单,对价格的影响力是不一样的。靠近最优价格的订单,影响力更大。所以我一般会用加权的方式:
def weighted_imbalance(book, levels=5):
bid_weighted = 0
ask_weighted = 0
for i in range(levels):
# 权重随档位递减
weight = 1.0 / (i + 1)
bid_price = sorted(book.bids.keys(), reverse=True)[i]
ask_price = sorted(book.asks.keys())[i]
bid_weighted += book.bids[bid_price] * weight
ask_weighted += book.asks[ask_price] * weight
return (bid_weighted - ask_weighted) / (bid_weighted + ask_weighted)
避坑指南:我曾经直接用原始OBI作为交易信号,结果回测表现很好,实盘却亏得一塌糊涂。后来发现,问题出在OBI对市场微观结构的变化太敏感。比如一个做市商撤单再重新挂单,就会造成OBI的剧烈波动,但这并不代表真正的买卖力量变化。所以我现在用OBI时,一定会加一个平滑处理,比如取过去N个事件的移动平均。
订单簿不平衡指标,说白了就是帮你判断「当前谁在主导市场」。如果买单深度明显大于卖单深度,价格大概率要往上走。但要注意,这个指标不是万能的。在消息驱动的行情中,订单簿可能瞬间被击穿,OBI会完全失效。
知识体系总览
下面这张图,是我自己梳理的订单簿微观结构知识框架。做高频做市,这些概念必须烂熟于心。
订单簿微观结构,是高频做市的基石。你只有理解了订单簿的每一层细节,才能在上面搭建出稳健的做市策略。下一章,我们会深入讨论如何利用这些微观结构特征,构建实际的做市算法。