订单簿与流动性分析:限价单与市价单、订单簿结构、流动性深度与滑点计算
大家好,我是你们的讲师。今天我们来聊聊订单簿和流动性分析。说实话,这部分内容是我在实战中踩坑最多的地方。刚入行那会儿,我总觉得算法交易就是写代码、算概率,直到有一次在流动性极差的币对上做了一笔大单,直接被打穿了三个档位——嗯,那笔亏损让我记住了什么叫「市场冲击」。
你想想看,如果你要买入100个比特币,而卖一档只有2个比特币,会发生什么?你的订单会像推土机一样,把卖单从低到高全部吃掉。这个过程产生的额外成本,就是滑点。而滑点的核心,就藏在订单簿的结构里。
一、限价单与市价单:两种订单的博弈
先说说最基础的两种订单类型。我个人习惯把限价单叫做「耐心单」,把市价单叫做「急迫单」。
- 限价单(Limit Order):你指定一个价格,只有市场达到这个价格才会成交。说白了,你在等别人来「接盘」或「割肉」。优点是你可以控制成交价格,缺点是不一定能成交。
- 市价单(Market Order):你不管价格,直接按当前最优价成交。优点是秒成交,缺点是你可能被「宰」——尤其是在流动性差的时候。
我在项目中遇到过一种情况:某个小币种,平时买卖价差只有0.1%,但一旦有大单进来,价差瞬间扩大到1%以上。为什么?因为做市商在撤单。他们看到你的大单,会立刻把限价单撤掉,然后重新挂更高的价格。这就是所谓的「抢跑」行为。
二、订单簿结构:读懂市场的「心电图」
订单簿,说白了就是所有未成交订单的集合。它分为买盘(Bid)和卖盘(Ask)两侧。每一侧都按价格从高到低排列。
举个例子,假设当前订单簿长这样:
| 价格 | 卖单数量 | 价格 | 买单数量 |
|---|---|---|---|
| 100.10 | 500 | 100.00 | 300 |
| 100.20 | 800 | 99.90 | 600 |
| 100.30 | 1200 | 99.80 | 900 |
这里卖一档是100.10,买一档是100.00。价差是0.10。如果你现在下市价买单,你会先吃掉100.10的500股,然后100.20的800股,以此类推。
为什么会这样?因为订单簿是按价格优先、时间优先的原则匹配的。价格好的先成交,价格相同的先到先得。
三、流动性深度:你的订单能「游」多远?
流动性深度,简单说就是订单簿上各个价格档位的订单总量。深度越厚,你的大单就越不容易造成价格大幅波动。
我一般用「深度曲线」来衡量流动性。横轴是价格偏移量,纵轴是累计成交量。比如:
# 计算累计深度
def calc_depth(order_book, side='ask', levels=10):
cumulative = 0
depth = []
for price, qty in order_book[side][:levels]:
cumulative += qty
depth.append((price, cumulative))
return depth
# 示例输出
ask_depth = calc_depth(order_book, 'ask', 5)
print(ask_depth)
# [(100.10, 500), (100.20, 1300), (100.30, 2500), ...]
你看,如果我要买2000股,按照上面的订单簿,我需要吃掉卖一到卖三的全部订单,成交均价是:
(100.10×500 + 100.20×800 + 100.30×700) / 2000 ≈ 100.205
比最优价100.10高了0.105。这就是滑点。
四、滑点计算:量化你的交易成本
滑点,就是你实际成交价与预期价之间的差额。它分为两种:
- 显性滑点:由订单簿上的价差和深度直接导致的滑点。可以精确计算。
- 隐性滑点:由你的订单本身对市场造成的影响导致的滑点。比如大单进场后,其他交易者会调整预期,导致价格进一步偏离。
计算显性滑点很简单:
def calc_slippage(order_book, side, quantity):
"""
计算市价单的预期滑点
side: 'buy' 或 'sell'
quantity: 交易数量
"""
total_cost = 0
remaining = quantity
for price, qty in order_book[side]:
if remaining <= 0:
break
trade_qty = min(remaining, qty)
total_cost += trade_qty * price
remaining -= trade_qty
if remaining > 0:
return None # 流动性不足
avg_price = total_cost / quantity
best_price = order_book[side][0][0]
slippage = (avg_price - best_price) / best_price * 100
return slippage
# 示例
slippage = calc_slippage(order_book, 'ask', 2000)
print(f"预期滑点: {slippage:.2f}%")
隐性滑点就复杂多了。它涉及到市场微观结构、信息不对称、以及你的订单对市场参与者心理的影响。我一般用「冲击成本模型」来估算,比如Almgren-Chriss模型:
# Almgren-Chriss 简化版
def impact_cost(quantity, volume, volatility, spread):
"""
quantity: 交易量
volume: 日均成交量
volatility: 波动率
spread: 买卖价差
"""
permanent = 0.1 * (quantity / volume) * volatility
temporary = 0.5 * spread * (quantity / volume)**0.5
return permanent + temporary
这个模型虽然简单,但在实际项目中已经够用了。我一般用它来估算大单的隐性成本,然后决定是否要拆单。
五、知识体系总览
下面这张图是我自己整理的,把本章的核心逻辑串起来了。你看一眼就能明白:订单类型、订单簿结构、流动性深度、滑点计算,它们之间是怎么关联的。
从这张图你可以看到,整个分析链条是:订单类型决定了你是提供还是消耗流动性 → 订单簿结构展示了当前市场的供需格局 → 流动性深度量化了你能「游」多远 → 滑点计算则把这一切转化为具体的成本数字。
好了,这一章的内容就到这里。记住,订单簿是你的「战场地图」,流动性是你的「弹药」,滑点是你的「战损」。只有把这三者搞清楚了,你的拆单算法才能真正做到「精准打击」。