第二章:订单簿与市场微观结构
做市策略的核心,说白了就是跟订单簿打交道。你想想看,我们每天看到的K线、成交量,其实都是订单簿的「投影」。真正的战场,在订单簿的每一层深度里。
我个人习惯把订单簿比作一个「实时拍卖场」。买方和卖方各自报价,价格撮合的过程,就是市场微观结构的全部秘密。
2.1 限价单与市价单:两种最基本的武器
先搞清楚这两个最基础的概念。我刚开始做量化时,觉得这太简单了,结果在实盘里吃过亏。
限价单(Limit Order)
你指定一个价格,挂在那里等。比如BTC当前价格30000,你想在29500买入,就挂个限价买单。只有价格跌到29500,你的单子才会成交。
- 优点:价格可控,不会滑点
- 缺点:可能永远成交不了
- 做市商最爱:我们就是靠挂限价单赚价差的
市价单(Market Order)
不管价格,直接吃掉对手盘。你输入买入数量,系统按当前最优卖价成交。
- 优点:立即成交,流动性好
- 缺点:可能滑点严重
- 做市商最怕:大额市价单会瞬间击穿我们的挂单
关键区别:限价单提供流动性,市价单消耗流动性。做市商本质上是「流动性提供者」,所以我们主要挂限价单。
2.2 订单簿的构建:从零开始搭一个
订单簿长什么样?其实就是两个列表:买单从高到低排,卖单从低到高排。中间那个空隙叫「价差」。
我记得第一次自己写订单簿数据结构时,用了Python的字典,结果性能惨不忍睹。后来才明白,高频场景下得用红黑树或者跳表。
# 一个简化的订单簿结构
class OrderBook:
def __init__(self):
self.bids = {} # 买单:价格 -> 数量
self.asks = {} # 卖单:价格 -> 数量
def add_order(self, side, price, quantity):
if side == 'buy':
self.bids[price] = self.bids.get(price, 0) + quantity
else:
self.asks[price] = self.asks.get(price, 0) + quantity
def get_top(self, n=5):
# 获取前n档深度
sorted_bids = sorted(self.bids.items(), reverse=True)[:n]
sorted_asks = sorted(self.asks.items())[:n]
return sorted_bids, sorted_asks
避坑指南:我曾经用浮点数做字典的key,结果因为精度问题导致订单匹配出错。后来统一用整数(价格乘以最小变动单位)来存储。
2.3 订单簿的动态变化:每一秒都在变
订单簿不是静态的。每一毫秒都有新单子进来,有单子被撤,有单子成交。做市商要实时跟踪这些变化。
常见的动态事件有四种:
- 新增订单:新的限价单挂进来,深度增加
- 撤单:挂单被取消,深度减少
- 成交:市价单吃掉限价单,深度变化
- 更新:部分成交后,剩余数量变化
你想想看,如果每秒有1000笔订单进来,你的系统能不能在1毫秒内更新完订单簿?这就是做市系统的核心挑战。
2.4 市场微观结构:藏在订单簿里的信号
订单簿不只是价格和数量。里面藏着很多信号,比如:
| 指标 | 含义 | 做市商怎么用 |
|---|---|---|
| 价差(Spread) | 最优卖价 - 最优买价 | 价差越大,做市利润越高 |
| 深度(Depth) | 各档位的挂单量 | 深度越厚,市场越稳定 |
| 订单失衡 | 买单总量 vs 卖单总量 | 失衡严重时,价格可能突变 |
| 撤单率 | 撤单数量 / 总挂单数量 | 撤单率高,说明有人在试探 |
注意:别只看最优档。我见过很多新手只盯着买一卖一,结果被中间层的「冰山订单」给坑了。大资金经常隐藏真实意图。
2.5 核心知识体系:一张图看懂
下面这张图是我自己总结的订单簿知识框架。做市策略的所有决策,都建立在这个结构之上。
2.6 实战中的几个坑
嗯,这里要注意几个实战中容易踩的坑:
- 数据延迟:你看到的订单簿可能已经滞后了50毫秒。在高频场景下,这足够让对手吃掉你的利润。
- 订单簿重建:断线重连后,要能快速重建订单簿。我习惯用增量更新+全量快照的方式。
- 冰山订单识别:如果某个价位频繁出现「撤单-重挂」的模式,大概率是冰山订单在试探。
我的经验:刚开始做回测时,我用的是1秒级别的快照数据。结果回测曲线漂亮得很,实盘一跑就亏。后来才发现,1秒内的订单簿变化太剧烈了,回测根本模拟不出来。现在我做回测至少用Tick级数据。
订单簿这东西,看着简单,里面门道很多。你把它研究透了,做市策略就成功了一半。
公众号:蓝海资料掘金营,微信deep3321