Ho-Stoll 做市商库存模型:把持仓风险写进最优报价
做市商的利润来自买卖价差,但风险来自库存:接了太多单边货,价格一个反向跳动就把几天赚的价差全吐回去。Ho-Stoll (1981) 把这个问题写成了一个随机最优控制:报价不该围绕市场中间价对称摆放,而应该围绕「保留价格」摆放——库存越偏多,整套报价越往下压;越偏空,越往上抬。本文从效用最大化出发推导保留价格与最优价差的闭式近似,用可复现 Python 模拟对比「无库存管理」与「库存偏移报价」两种做市商:后者把库存从随机游走驯化成均值回复过程,库存标准差从 16 股压到 1 股以内。并诚实拆解模型的失效场景:趋势市中的逆向选择、参数校准的现实困难、以及它和 Avellaneda-Stoikov 的关系(中阶)。
一个做市商的两难#
做市商的商业模式说穿了很简单:同时挂出买价和卖价,别人买你就卖、别人卖你就买,每一对成交赚一个价差。听起来是稳赚的搬运工生意。
但有个致命的角色错位:做市商不能选择自己的持仓,持仓是被客户订单流塞给他的。连续来了二十个卖单,他手上就多了二十份货;这时候价格往下跳 1%,二十份货的浮亏可能超过他一整天赚的价差。
于是问题变成:手上已经压了一堆多头库存时,报价还应该和空仓时一样吗?
直觉说不该——应该急着把货卖掉、不想再接货。Ho 和 Stoll 在 1981 年把这个直觉写成了严格的随机最优控制问题,答案出乎意料地干净:报价不该围绕市场中间价对称摆放,而该围绕一个随库存移动的「保留价格」对称摆放。

保留价格:库存的价格化#
模型设定#
Ho-Stoll 框架里的做市商是这样一个人:
- 对某只股票持有库存 (正为多头,负为空头),股票真实价值 ,价格波动率 ;
- 他厌恶风险,效用函数为指数型 , 是风险厌恶系数;
- 他要在剩余时间 内挂买卖报价,订单以某种概率到达,到达概率取决于报价的激进程度;
- 目标:最大化期末财富的期望效用。
保留价格的推导#
先问一个更基础的问题:持有库存 的做市商,愿意以什么价格无差异地多卖一股?
这个价格叫保留价格(reservation price)。在指数效用 + 正态价格假设下,持有 股、剩余时间 的确定性等价财富是:
第一项是库存的期望价值,第二项是风险惩罚——注意它对 是二次的:库存翻倍,风险惩罚翻四倍。这就是为什么做市商对大库存如此敏感。
多卖一股的边际价值就是 对 的导数,取负号得到保留价格:
这条公式是整个模型的灵魂。它说:
- 空仓时(),保留价格就是市场中间价 ,报价对称;
- 多头库存(),保留价格低于中间价——做市商心里对这只股票的”内部估值”打了折扣,因为再多接一股的风险惩罚在上升。于是 bid 和 ask 整体下移:卖价压得更低(急着出货),买价也压得更低(不想接货);
- 空头库存()则整体上抬,逻辑对称。
注意一个容易搞错的点:偏移的不是价差,而是价差的中心。最优价差本身(下一节推)和库存无关,库存只决定这个价差挂在哪个高度。
最优价差#
价差的宽度由另一组权衡决定:挂得宽,每笔成交赚得多但成交概率低;挂得窄,成交频繁但每笔赚得薄,而且库存周转带来的风险敞口时间更长。Ho-Stoll 的解在一阶近似下:
其中 是订单处理成本(交易费、系统成本等硬下限)。价差随风险厌恶和方差线性放大:

这解释了两个日常观察:波动率高的股票价差更宽;同一只股票在财报日、宏观数据发布日价差被拉宽——都是 在起作用,做市商在为承担存货风险要求更高补偿。
用 Python 验证:库存偏移到底值不值#
理论说完了,上代码。我们模拟两个做市商在同一个市场里做市:
- 做市商 A(naive):报价永远围绕市场中间价对称,完全不管库存;
- 做市商 B(Ho-Stoll):报价围绕保留价格 对称。
订单到达概率随报价激进程度衰减(报价离中间价越远,被成交的概率越低),这是对 Ho-Stoll 中订单到达函数的标准简化:
import numpy as np
def simulate_mm(gamma_skew, n_steps=5000, seed=7):
"""gamma_skew=0 复现 naive 做市商;>0 为 Ho-Stoll 式库存偏移。"""
rng = np.random.default_rng(seed)
mid = 100.0
sigma_step = 0.03 # 中间价每步波动
half = 0.05 # 半价差
k = 1.2 # 订单到达对报价激进度的敏感度
A = 0.9 # 基础到达强度
q, cash = 0.0, 0.0
invs, pnls = [], []
for t in range(n_steps):
mid += rng.normal(0, sigma_step) # 中间价随机游走
r = mid - gamma_skew * q # 保留价格:核心一行
bid, ask = r - half, r + half
# 报价越靠近中间价,被动成交概率越高
p_sell = A * np.exp(-k * (ask - mid) / half) * 0.5
p_buy = A * np.exp(-k * (mid - bid) / half) * 0.5
if rng.random() < min(p_sell, 0.95): # 对手方吃掉卖单
q -= 1; cash += ask
if rng.random() < min(p_buy, 0.95): # 对手方砸中买单
q += 1; cash -= bid
invs.append(q)
pnls.append(cash + q * mid) # 盯市 P&L
return np.array(invs), np.array(pnls)
inv_naive, pnl_naive = simulate_mm(0.0)
inv_hs, pnl_hs = simulate_mm(0.02)
print(f"naive: 库存σ={inv_naive.std():.1f} 库存峰值={abs(inv_naive).max():.0f}")
print(f"Ho-Stoll: 库存σ={inv_hs.std():.2f} 库存峰值={abs(inv_hs).max():.0f}")python5000 步模拟的结果:
naive: 库存σ=16.1 库存峰值=48
Ho-Stoll: 库存σ=0.97 库存峰值=4plaintext
差距是数量级的。机制上看得很清楚:
Naive 做市商的库存是随机游走。 买卖成交概率永远对称,库存增量均值为零但方差随时间线性累积——运气不好时库存能飘到 ±48 股,这时候中间价一个 1 元的反向移动就是 48 元的浮亏,而他每笔成交只赚 0.05 元的半价差。
Ho-Stoll 做市商的库存是 OU 式均值回复过程。 库存一偏多,报价整体下压:卖价更接近中间价(更容易被吃掉、加速出货),买价离中间价更远(更难被砸中、抑制进货)。两个力都在把 推回零。回复速度正比于 ,这正是连续时间里 OU 过程的回复系数。

分布图更直观:naive 的库存散布在 ±40 的宽区间,Ho-Stoll 的库存被死死压缩在 ±3 以内。
代价是什么?Ho-Stoll 做市商偏移报价时,有一侧报价离中间价更远、成交概率更低,牺牲了一部分价差捕获量。但在这次模拟中两者终值 P&L 几乎相同(52.3 vs 55.9),因为 naive 省下的报价优势被库存浮亏波动完全抵消了。在风险调整后口径下,Ho-Stoll 全面占优——这正是模型的核心承诺:用一点点期望收益换掉大部分存货风险,对风险厌恶的做市商是严格改进。
从 Ho-Stoll 到 Avellaneda-Stoikov#
如果你接触过做市策略,大概率听过 Avellaneda-Stoikov (2008)。值得说清楚两者的关系:AS 本质上是 Ho-Stoll 在连续时间 + 指数效用 + 泊松订单到达下的现代重写。AS 的两条著名公式:
第一条就是本文的保留价格(多了随时间衰减的 项:越接近收盘,留给库存出清的时间越少,但同时剩余持有风险也在缩短);第二条的最优价差在 小时退化为 Ho-Stoll 的线性形式。读懂了 Ho-Stoll,AS 就只是换了一套更精细的数学衣服。
实务中加密货币和股票高频做市广泛使用的”库存偏移报价”(inventory skew),不管实现得多工程化,内核都是那一行 r = mid - gamma * q。
模型的诚实边界#
Ho-Stoll 优雅,但有三个不能装看不见的问题。
第一,它假设订单流没有信息。 模型里订单到达是外生随机的,和未来价格无关。现实里恰恰相反:连续砸过来的卖单往往意味着有人知道了什么(逆向选择)。趋势市里,Ho-Stoll 做市商会一路降价接货、库存偏移报价加速出货——但出货速度赶不上价格下跌速度,本质上是在给知情交易者送钱。这个维度由 Glosten-Milgrom / Kyle 一系信息模型处理,成熟的做市系统必须同时建模两者:库存项管风险,逆向选择项管毒性订单流(比如用 VPIN 或短窗价格冲击来调 的估计)。
第二,参数校准是真正的难点。 不是市场可观测量,是自己的风险偏好,实务中通常反过来定:先决定”库存达到 X 时报价偏移 Y 个 tick”这样的业务约束,再反解 。 用已实现波动率估计则要小心日内季节性——开盘半小时的 是午盘的 3 倍,用全天平均值会导致开盘时价差挂太窄、被单边流打穿。
第三,模拟里的订单到达函数是玩具。 真实的成交概率取决于队列位置、tick 大小、对手方构成,指数衰减形式只是可解性妥协。这不影响”库存均值回复”这个定性结论,但影响最优参数的具体数值——任何直接把本文参数搬进实盘的行为都等于没读这一节。
收尾#
Ho-Stoll 模型用一条一阶导数把”库存焦虑”翻译成了报价语言:保留价格 ,价差中心随库存线性平移。模拟验证了它的核心承诺——库存标准差从 16 压到 1 以内,P&L 几乎不受损。
对量化交易者,这个模型的价值不限于做市:任何需要”被动挂单 + 管理净敞口”的执行策略(比如大单拆分时的 passive 挂单侧),都能用库存偏移的思路控制执行过程中的存货风险。而它最重要的教训是方法论上的:风险不是事后统计出来的,是可以事前写进每一次报价里的。
参考文献#
- Ho, T., & Stoll, H. R. (1981). Optimal dealer pricing under transactions and return uncertainty. Journal of Financial Economics, 9(1), 47-73.
- Avellaneda, M., & Stoikov, S. (2008). High-frequency trading in a limit order book. Quantitative Finance, 8(3), 217-224.
- Guéant, O., Lehalle, C-A., & Fernandez-Tapia, J. (2013). Dealing with the inventory risk: a solution to the market making problem. Mathematics and Financial Economics, 7(4), 477-507.