市场微观结构与订单簿基础
:::info 学习目标 你将能读懂订单簿档位、计算中间价/有效价差/VWAP,并区分临时冲击、永久冲击、排队风险和逆向选择。 :::
直觉
前面所有模块都假设「想买就能按收盘价买到」——这是研究者的视角。实盘里,你的订单要进入限价订单簿(LOB):买单和卖单排队匹配。买得少,按最便宜的卖价成交;买得多,就要一层层吃掉卖盘,越买越贵——这就是价量冲击(price impact)。微观结构研究的就是「订单如何在真实簿子里成交、并对价格造成多大冲击」,它是连接「理论信号」与「可实现的 PnL」的最后一公里。
订单簿、买卖价差与冲击
- 中间价 ;买卖价差 ;
- 市价单吃对手盘(提供流动性者付钱给你?不——你付价差),限价单挂单排队赚价差;
- 价量冲击(Kyle 线性模型):,订单量 越大、价格滑点越大, 是「市场深度」的倒数。
「人话」解释:市价单为什么「越买越贵」?
簿子里最便宜的卖价只有那么几股。你下一个 100 股的小单,按最便宜卖价成交;但下一个 10000 股的大单,便宜的卖盘被吃光后,系统会自动匹配更贵的下一档、再下一档……你的平均成交价(VWAP)就被越抬越高。这多付的部分就是冲击成本,是回测里最容易被忽略、实盘里最真实存在的损耗。流动性差的小盘股 大,同样金额冲击贵得多——这正是为什么很多策略在标普大盘上有效、下到小盘股就消失。
可运行案例:市价单的价量冲击
构造一个卖盘逐档变薄的订单簿快照,模拟买入不同数量时的 VWAP 滑点——直观看到「单子越大,越容易吃到更贵、更薄的档位」。
import numpy as np
import matplotlib.pyplot as plt
mid, tick, levels = 100.0, 0.01, 20
asks = [mid + (i+1)*tick for i in range(levels)] # 卖盘: 越往上越贵
ask_sizes = np.linspace(500, 100, levels).astype(int) # 远端流动性更薄,总深度约 6000 股
def buy_vwap(q): # 市价买入 q 股, 逐档吃卖盘
rem, spent = q, 0.0
for px, sz in zip(asks, ask_sizes):
take = min(rem, sz); spent += take*px; rem -= take
if rem <= 0: break
if rem > 0: return None # 簿子不够深
return spent / q
print(f"有效价差(吃第1档) = {(asks[0]-mid)/mid:.4%}")
sizes = np.arange(300, sum(ask_sizes) + 1, 300) # 从正数量开始,避免 q=0
slip = [(buy_vwap(q)-mid)/mid*1e4 for q in sizes] # 滑点(bps)
print(f"买 300 股 滑点={slip[0]:.2f}bps 买 {sizes[-1]} 股 滑点={slip[-1]:.2f}bps")
plt.figure(figsize=(9, 3.4))
plt.plot(sizes, slip, color='darkorange', lw=1.6)
plt.xlabel('市价买单股数'); plt.ylabel('滑点 (bps)')
plt.title('价量冲击:订单越大,VWAP 滑点加速上升'); plt.tight_layout(); plt.show()
print("\n→ 回测若假设按中间价成交, 会系统性高估大单策略的真实 PnL。")
从快照到真实成交
订单簿快照没有展示订单到达、撤单和队列位置。限价单虽可能赚价差,却承担不成交和逆向选择:最容易成交时往往正是价格即将朝不利方向移动。冲击还分为随后回落的临时部分与反映信息的永久部分,二者对执行速度的含义相反。
实践与延伸
- 让每档深度随机变化,比较相同订单量下滑点分布而非单点值。
- 模拟限价单排队与撤单,统计成交概率和成交后的价格漂移。
延伸阅读:O'Hara《Market Microstructure Theory》;Kyle(1985)连续拍卖模型。
小结
- 订单在限价订单簿里匹配:中间价、买卖价差、档位深度;
- 市价单付价差 + 吃深度的冲击,量越大滑点凸性越高();
- 策略落地必须把冲击成本算进去——这是研究与实盘 PnL 的主要落差来源之一。
章末自测
检查核心概念
1. 关于本章主题,哪项说法更准确?