第二章 订单簿微观结构:限价单与市价单、订单簿的构建、买卖价差与市场深度
做市商这行,说白了就是跟订单簿打交道。你每天盯着的那个不断跳动的数字墙,就是你的战场。我刚开始做量化的时候,总觉得订单簿就是个简单的买卖队列,后来吃了不少亏才明白——这玩意儿里面的门道深着呢。
2.1 限价单与市价单:两种最基本的武器
先说说最基础的东西。订单簿里只有两种订单:限价单和市价单。嗯,就这么简单,但组合起来能玩出花来。
限价单(Limit Order),就是你指定一个价格,挂在那里等别人来成交。比如你觉得BTC现在30000美元太贵了,想等它跌到29500再买,那就挂个限价买单。这玩意儿提供流动性,是咱们做市商的主要工具。
市价单(Market Order),就是不管三七二十一,按当前市场上最好的价格立刻成交。你想马上买入,那就吃一口卖一价的单子。这玩意儿消耗流动性,是交易员和散户常用的。
核心区别:
- 限价单:提供流动性,承担不成交的风险,但能控制价格
- 市价单:消耗流动性,保证成交,但可能滑点严重
我在项目中遇到过一件事。有一次我们做ETH的做市,有个新手同事挂了一堆限价单,结果行情突然暴跌,他的买单全被吃了,价格还在往下砸。他慌了,想撤单,但撤单速度跟不上行情变化。最后亏了不少。所以啊,限价单不是随便挂的,你得考虑市场冲击和撤单延迟。
2.2 订单簿的构建:从原始数据到实时状态机
订单簿怎么构建的?说白了就是维护两个有序列表:买单列表(Bids)和卖单列表(Asks)。买单按价格从高到低排,卖单按价格从低到高排。每个价格档位后面跟着该价格的总挂单量。
我习惯用Python来处理这个。给你看个简单的数据结构:
class OrderBook:
def __init__(self):
self.bids = {} # 价格 -> 数量
self.asks = {} # 价格 -> 数量
self.bid_levels = [] # 排序后的买单价格列表
self.ask_levels = [] # 排序后的卖单价格列表
def update(self, side, price, quantity):
if quantity == 0:
# 删除该价格档位
if side == 'bid':
self.bids.pop(price, None)
else:
self.asks.pop(price, None)
else:
# 更新或新增
if side == 'bid':
self.bids[price] = quantity
else:
self.asks[price] = quantity
# 重新排序
self.bid_levels = sorted(self.bids.keys(), reverse=True)
self.ask_levels = sorted(self.asks.keys())
你想想看,交易所每秒会推送成千上万条订单簿更新。你如果每次都重新排序整个列表,性能肯定跟不上。我建议用红黑树或者跳表这种有序数据结构来维护。C++里用std::map,Python里可以用sortedcontainers库。
避坑指南:我曾经犯过一个错误——直接用字典存订单簿,每次更新都全量排序。结果回测跑得飞快,实盘一上就卡死了。后来改成增量更新,只维护价格档位的变化,性能提升了10倍不止。
2.3 买卖价差:做市商的利润来源
买卖价差(Bid-Ask Spread),就是卖一价减去买一价。这是做市商的核心利润来源。你低价买入,高价卖出,中间的差价就是你的收入。
但价差不是固定的。它受很多因素影响:
- 流动性:交易量大的币种,价差通常很小。BTC/USDT的价差可能只有0.01%,而一些小币种可能达到0.5%甚至更高。
- 波动性:行情剧烈波动时,做市商为了控制风险,会主动拉大价差。
- 时间:凌晨流动性差,价差会变大。我一般会在凌晨调低挂单量,避免被大单吃掉。
- 交易所:不同交易所的价差不一样。我记得有一次在某个二线交易所做市,价差是币安的3倍,但成交量只有币安的十分之一。
咱们做市商怎么定价?我常用的一个公式:
spread = base_spread + k * volatility + c * (1 / sqrt(volume))
其中:
- base_spread: 基础价差,根据币种和交易所设定
- k: 波动率系数,一般取0.5-2.0
- volatility: 近期波动率,可以用5分钟或15分钟的收益率标准差
- c: 流动性系数
- volume: 近期的成交量
这个公式不是万能的,但能给你一个起点。实际跑起来还得根据市场反馈不断调整。
2.4 市场深度:你的护城河有多宽
市场深度(Market Depth),就是订单簿上各个价格档位的挂单量总和。深度越大,说明市场越能承受大额交易而不产生大的价格波动。
我习惯看两个指标:
- 深度表(Depth Table):列出前N档的累计挂单量。比如买一到买五的总量是多少。
- 深度图(Depth Chart):把买单和卖单的累计量画成曲线,能直观看到市场的支撑和阻力位。
给你看个深度表的例子:
| 档位 | 买单价格 | 买单数量 | 累计买单 | 卖单价格 | 卖单数量 | 累计卖单 |
|---|---|---|---|---|---|---|
| 1 | 29950 | 12.5 | 12.5 | 30050 | 8.3 | 8.3 |
| 2 | 29900 | 20.1 | 32.6 | 30100 | 15.7 | 24.0 |
| 3 | 29850 | 35.0 | 67.6 | 30150 | 22.3 | 46.3 |
| 4 | 29800 | 18.2 | 85.8 | 30200 | 30.0 | 76.3 |
| 5 | 29750 | 42.0 | 127.8 | 30250 | 25.5 | 101.8 |
从这张表能看出什么?买单深度明显比卖单深。这说明市场在30000美元附近有较强的支撑。如果我是做市商,我会在卖单这边挂得稍微保守一点,避免被大单砸穿。
注意:深度数据是动态变化的。你以为买一有100个BTC撑着,下一秒可能就被撤单了。我见过有人根据深度数据做套利,结果撤单瞬间亏了十几万。所以啊,深度数据只能作为参考,不能完全依赖。
2.5 订单簿微观结构的核心逻辑
说了这么多,咱们来画张图,把整个知识体系串起来。
这张图把咱们刚才讲的内容串起来了。订单簿是核心,左边是订单类型,中间是构建方法,右边是核心指标。最下面那条虚线表示反馈循环——市场深度变化会影响你的策略,你的策略又会反过来影响订单簿。
做市商说白了就是在跟市场博弈。你挂单,别人吃单;别人挂单,你吃单。谁的信息更全、反应更快、策略更优,谁就能赚钱。嗯,这就是博弈论在订单簿上的体现。
我的习惯:每天开盘前,我会先看一遍主要交易对的订单簿结构。哪个价格档位有大量挂单,哪个位置有支撑或阻力,心里有个数。然后根据这些信息调整当天的做市参数。这花不了几分钟,但能帮你避开很多坑。
好了,订单簿微观结构就讲到这里。记住一句话:订单簿是你的战场,限价单和市价单是你的武器,价差和深度是你的护城河。把这些搞明白了,做市商的路就走稳了一半。
公众号:蓝海资料掘金营,微信deep3321