halo 的技术博客

返回

问题:做市商到底在赚什么、又在怕什么#

做市(market making)表面上是一门”两头赚差价”的生意:在买一挂个买单、在卖一挂个卖单,被买方成交一次、卖方成交一次,就赚到一个价差。听起来像永动机。

但真做过的人都知道,做市的敌人不是”赚不到价差”,而是库存。当你的买单被大量成交,你手里就堆了一堆多头库存 q>0q>0;如果这时候市场往下走,你的存货就在亏钱——你赚的那点价差远不够填坑。做市商的核心矛盾是:想多成交(多赚价差)就得把报价挂得离中间价近,但挂得越近、成交越频繁,库存越容易失控

Avellaneda & Stoikov 在 2008 年给了这个矛盾一个漂亮的解析解。它的核心洞察是:不要围绕中间价对称报价,要围绕一个”保留价格”报价,而这个保留价格会随你手里的库存自动偏移——库存多就整体下移(引导别人从你这买走、去库存),库存空就整体上移(引导别人卖给你、补库存)。

本文用一个固定随机种子(20260801)、200 步的 tick 级受控模拟,从零把这个模型跑出来,回答三个问题:A-S 的库存偏移到底值多少钱?风险厌恶 γ 这根旋钮怎么调?以及最重要的——这套东西在真实世界里还剩多少?

先把结论摆前面:在教科书参数下,A-S 相对朴素对称做市把库存方差砍掉 86.3%、夏普从 4.71 翻到 9.04;但这个夏普 9 本身就是个危险信号,加入未知趋势和每笔成本后,它会在几档之内崩到 0.84、破产概率抬到 14%。

模型与模拟设计#

三个核心公式#

保留价格(reservation price)——做市商心里真正的”公允价”,随库存 qq 线性偏移:

r(s,q,t)=sqγσ2(Tt)r(s, q, t) = s - q \cdot \gamma \cdot \sigma^2 \cdot (T - t)

其中 ss 是中间价,qq 是当前库存,γ\gamma 是风险厌恶,σ\sigma 是波动率,TtT-t 是到收盘的剩余时间。库存为正时 r<sr<s(心里价比市场价低,急着卖);库存为负时 r>sr>s(急着买)。

最优总价差(optimal spread)——买卖两个报价的总宽度:

δa+δb=γσ2(Tt)+2γln(1+γκ)\delta^a + \delta^b = \gamma \sigma^2 (T - t) + \frac{2}{\gamma} \ln\left(1 + \frac{\gamma}{\kappa}\right)

它由两块拼成:前一项 γσ2(Tt)\gamma\sigma^2(T-t)库存风险项(越怕风险、波动越大、离收盘越远,价差越宽);后一项 2γln(1+γ/κ)\frac{2}{\gamma}\ln(1+\gamma/\kappa)成交激励项(由订单簿深度 κ\kappa 决定,是你愿意为”多成交”让出的利润)。

报价摆放:买卖报价围绕保留价格 rr 对称摆放,而不是围绕中间价 ss

pa=r+spread2,pb=rspread2p^a = r + \frac{\text{spread}}{2}, \qquad p^b = r - \frac{\text{spread}}{2}

成交强度:一个报价离中间价越远,越不容易成交。成交强度按指数衰减:

λ(δ)=Aeκδ\lambda(\delta) = A \cdot e^{-\kappa \delta}

在每个时间步 dtdt 内成交的概率取 1eλdt1 - e^{-\lambda dt}

模拟设定#

中间价走几何布朗式随机游走(ds=σdtZds = \sigma\sqrt{dt}\,Z),初始价 s0=100s_0=100σ=2\sigma=2,交易周期 T=1T=1(一个交易日归一化),步长 dt=0.005dt=0.005(共 200 步)。基准参数 γ=0.1\gamma=0.1κ=1.5\kappa=1.5A=140A=140。做市商每一步按 A-S 最优报价挂买卖单,成交后更新库存 qq 与现金,终端 PnL = 现金 + 库存按收盘中间价的市值。全部用 numpy 向量化,几千条路径同步推进。

对抗式检验:先证明公式没写错#

在跑任何模拟之前,先用三个极限情形做 sanity check——一个连极限都过不了的实现,出的数字再漂亮也是假的:

  1. 库存为 0 时,保留价格必须等于中间价r(s,0,t)=sr(s,0,t)=s。✅ 通过。
  2. 零波动率时,价差退化为纯成交激励项:令 σ=0\sigma=0,库存风险项归零,价差应只剩 2γln(1+γ/κ)\frac{2}{\gamma}\ln(1+\gamma/\kappa)。实测价差 = 1.290770,与解析激励项 1.290770 完全吻合。✅
  3. γ→0 时,价差收敛到 2/κ2/\kappa,库存偏移项归零:当风险厌恶趋近于 0,2γln(1+γ/κ)2/κ\frac{2}{\gamma}\ln(1+\gamma/\kappa)\to 2/\kappa,策略退化为激进的对称做市。实测 γ=1e-7 时价差 = 1.333334,理论 2/κ2/\kappa = 1.333333。✅

三项全过。作为对照,基准参数下(γ=0.1\gamma=0.1)开盘时的完整最优价差是 1.690770(= 库存风险项 0.4 + 激励项 1.29077),后面所有结果都建立在这个已验证的引擎上。

逐图分析#

图1:保留价格如何随库存偏移#

单路径:中间价、买卖报价、保留价格与库存

上图是单条路径的完整演示。黑线是中间价 ss,红色虚线是保留价格 rr,蓝绿两条细线是卖出/买入报价。关键看红线相对黑线的偏移:下方库存面板显示库存为红色(净多头)的时段,保留价格与整条报价带整体压在中间价下方——做市商在”降价甩货”;库存翻绿(净空头)时,报价带整体抬到中间价上方——在”抬价补货”。

这不是视觉错觉:这条路径上库存与”保留价-中间价”偏移的相关系数是 −0.6169,负相关正是模型的设计意图。库存最大绝对值到过 6 手。还有一个容易忽略的细节:越靠近收盘(t1t\to 1),Tt0T-t\to 0,库存风险项消失,报价带重新收敛成围绕中间价对称——因为再没有时间被库存反噬了。

图2:A-S vs 朴素对称做市,库存方差砍掉 86%#

A-S 与对称做市的库存与 PnL 分布对比

这是全文最核心的对照。对手是”朴素对称做市”:用同样宽度的价差,但永远对称挂在中间价两侧、完全无视库存。4000 条路径下:

  • 终端库存:对称做市的库存标准差 8.14、平均绝对库存 6.48 手;A-S 是 3.01 和 2.37 手。库存方差降低 86.3%。左图里橙色(对称)胖而散,蓝色(A-S)瘦而聚。
  • 终端 PnL:对称做市均值 60.86、标准差 12.92;A-S 均值 57.11、标准差 6.32

读法要诚实:A-S 的期望利润其实略低(57.1 vs 60.9,因为它为了控库存有时会主动错过成交)。但它把 PnL 波动几乎砍半。两者一除,A-S 的夏普是 9.04,对称做市只有 4.71——控住库存换来的风险调整收益几乎翻倍。这就是 A-S 的全部价值:它不是让你多赚,是让你赚得更稳

图3:风险厌恶 γ 是一根有代价的旋钮#

风险收益前沿:期望利润 vs 库存风险

γ 不是越大越好,也不是越小越好,它是一条有效前沿上的位置选择。扫描 γ 从 0.01 到 1.0:

γ期望利润库存标准差 σ(q)成交笔数开盘价差夏普
0.0160.275.3590.31.376.63
0.1057.153.0485.41.699.18
0.3547.982.1574.82.608.22
1.0028.231.6850.45.026.17

机制很清楚(右图):γ↑ → 价差变宽 → 成交量下降 → 期望利润下降,但同时库存风险也被压得更小。左图的散点连成一条向右上凸的前沿:想要更低的库存风险,必须交出期望利润。有意思的是夏普并非单调——它在 γ≈0.1 附近见顶(9.18),因为 γ 太小则库存失控(分母大),太大则利润被价差挤没(分子小)。这说明”最优风险厌恶”是个可优化的中间值,不是拍脑袋的极端。

图4:泼冷水——教科书里的印钞机,一碰现实就崩#

PnL 蒙特卡洛分布:教科书幻觉 vs 真实尾部

到这里为止,A-S 看起来完美得可疑:6000 条路径的中性市场里,均值 57.06、夏普 9.00、破产概率 0%、最差的一条也赚 31.54。一个夏普 9、从不亏钱的策略——这本身就是最大的危险信号。真实做市桌子上没有人的夏普是 9。

问题出在哪?出在两个被教科书假设掉的东西:

一是未知趋势(毒性流/知情交易)。 我给每条路径注入一个未知漂移(drift_sig\text{drift\_sig},代表”这天到底是趋势市还是震荡市”你事先不知道)。当市场真出趋势,做市商的库存会被反复往一个方向打——你的卖单一直被知情买家吃掉,库存越来越空,而价格还在涨,补回来的成本越来越高。扫描下来:趋势强度从 0 升到 18,夏普从 9.26 一路压到 5.09,最差路径从 +37.6 掉到 −16.4。趋势没能制造大面积破产(因为价差收入太厚),但它实实在在地咬掉了一半的风险调整收益。

二是每笔成本(手续费 + 竞争压缩价差 + 逆向选择)。 现实里价差不是你说了算,是被竞争压出来的,而且你每笔成交都要付费、还系统性地在坏价格上被知情方成交。我在”趋势市”基础上叠加一个每笔单边成本,扫描结果是全文最冷的一张表:

每笔成本均值 PnL夏普破产概率
0.0057.096.480.0%
0.3031.424.100.1%
0.4518.642.641.0%
0.605.760.8114.0%
0.90−19.86−2.7599.0%

在”趋势 + 每笔 0.6 成本”的现实情景下(右图红色分布),均值 PnL 从 57 塌到 5.83、夏普从 9 塌到 0.84、破产概率从 0 抬到 14%、最差路径亏 42.6。而当成本升到 0.9(约半个价差的量级),99% 的路径都在亏钱。左图两条分布的对比极其刺眼:蓝色是教科书幻觉,红色是加了两桶冷水后的真实尾部。

结论:杀死朴素 A-S 的不是库存风险本身(A-S 恰恰把库存控得很好),而是竞争与成本对价差的侵蚀。整套模型的全部利润都活在”你能以低成本捕获一个够宽的价差”这个假设里,一旦这个假设松动,边际就在几档之内蒸发。

关键代码:报价逻辑#

整个策略的心脏其实只有几行——每一步计算保留价格、算最优价差、围绕保留价格摆买卖单,然后用指数强度决定是否成交:

A-S 分支和对称分支的唯一区别,就是报价围绕 r 还是围绕 s——一行之差,换来 86% 的库存方差降低。

三段式总结#

A. 实现细节#

  • 信号与执行时点:每一步先用当前中间价 ss 和库存 qq 算报价(signal-on-i),同一步内判定是否成交(execute-on-i),成交结算完再让中间价游走一步。避免用未来价格反算当期成交。
  • 成交判定:每步每边成交概率取 1eλdt1-e^{-\lambda dt}(Poisson 首次到达),λ=Aeκδ\lambda=A e^{-\kappa\delta}。成交只判”成/不成”,单位成交量固定为 1 手(A-S 原始设定)。
  • PnL 口径:终端 PnL = 累计现金流 + 终端库存 × 收盘中间价,即库存按市价 mark-to-market,不做提前平仓。
  • 对称基准的公平性:对称做市用与 A-S 完全相同的价差公式和同一批价格随机数,唯一区别是报价中心(ss vs rr),确保对比只反映”库存偏移”这一个变量。
  • 成本与趋势建模cost 为每笔单边成本(现金流中直接扣减),drift 支持每条路径抽一个未知漂移来模拟毒性流/趋势市。全程固定种子 20260801

B. 已知偏差#

  • 中间价是无漂移 GBM,且波动率 σ\sigma 对做市商完全已知——这是 A-S 相对现实最大的美化。真实 σ\sigma 要估计、会跳、有厚尾,估错 σ\sigma 会直接算错价差。
  • 成交强度参数 A,κA,\kappa 恒定且已知:真实订单簿深度随行情剧烈变化,κ\kappa 在波动时会塌。
  • 无队列/延迟/被抢单:模型假设你的报价一挂就在队首,忽略了排队优先级、撤改单延迟、被更快的对手抢成交——这些在真实做市里往往是胜负手。
  • 逆向选择建模是粗粒度的:本文用”每笔成本”作为竞争+逆向选择的合并代理,没有显式区分”知情单打你”和”手续费”,也没做成交概率的买卖不对称。
  • 单标的、单位成交量:忽略了多品种对冲、成交量分布、以及大库存对自身报价的冲击。

C. 结果解读#

  • 库存偏移是真价值,但价值形式是”降险”不是”增收”:A-S 期望利润比对称做市还低 6%(57.1 vs 60.9),它的贡献全在把库存方差砍掉 86.3%、夏普翻倍(4.71→9.04)。如果你的目标函数只看总收益不看波动,A-S 对你没意义。
  • γ 有最优中值,不是极端:夏普在 γ≈0.1 见顶(9.18),过小库存失控、过大利润被价差挤没。调 γ 本质是在”库存方差”和”期望利润”这条前沿上选点。
  • 利润来源高度集中于价差捕获:中性市场里库存与终端 PnL 几乎不相关(因为库存被 A-S 控住了),说明钱主要来自稳定的价差收入,而非方向性押注——这既是优点(稳),也是软肋(一旦价差被压缩,利润无处可寻)。
  • 真正的尾部来自成本而非库存:趋势市把夏普从 9.3 压到 5.1 但几乎不制造破产;而每笔 0.6 的成本就能把夏普打到 0.84、破产概率抬到 14%,0.9 时 99% 亏损。这告诉你把研发精力放哪:不是继续优化库存控制,而是死磕成交成本、排队优先级和价差竞争。
  • 可交易性冷水:教科书参数下的夏普 9、零破产是一面镜子——任何回测里出现这种数字,第一反应应该是”我假设掉了什么”,而不是”我发财了”。A-S 是理解做市结构的绝佳框架,但直接照搬它的报价去实盘,等于假设自己能免费捕获一个宽价差,这个假设在有竞争的市场里几乎不成立。
Avellaneda-Stoikov 做市:用库存风险与最优报价拆解买卖价差
https://blog.halo26812.eu.org/blog/avellaneda-stoikov-market-making
Author halo
Published at 2026年8月1日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨