返回 Expert 笔记
Expert Day 76

价格发现 (Kyle 1985 & Glosten-Milgrom 1985)

Kyle (1985) 单期/多期 batch auction、Glosten-Milgrom 逐笔模型、informed vs noise trader、lambda 推导

2026-07-16
Phase 2 - 市场微观结构与做市 (Day 75-88)
做市微观结构KyleGlostenMilgrom价格发现

日期: 2026-07-16 方向: 量化 / 微观结构 / 做市 阶段: Phase 2 - 市场微观结构与做市 (Day 75-88) 标签: #做市 #微观结构 #Kyle #GlostenMilgrom #价格发现


今日目标

类型内容
学习Kyle (1985) 单期/多期 batch auction、Glosten-Milgrom 逐笔模型、informed vs noise trader、lambda 推导
实操Kyle 模型 Monte Carlo 仿真、验证 λ = √(σ_v² / σ_u²) /2、price impact 收敛
产出kyle.py:单期解析解 + 多期 RNN 解 + GM 贝叶斯更新 + 与 Binance trade flow 对比

Kyle 模型是市场微观结构的"F=ma"。理解 λ(信息不对称如何转化为价格冲击)是做市建模的起点。


一、为什么需要价格发现模型?

昨天我们看到 LOB 是"机制"。但价格本身是怎么形成的

经典金融假设:价格 = 公允价值(CAPM、APT)。但市场上有人比你知道得更多——内部信息、研究、私有数据。做市的核心痛点:和你成交的对手,可能是知情者(informed),也可能是流动性需求者(uninformed / noise)。

  • 跟 informed 成交 → 价格 marche 你 → adverse selection 损失
  • 跟 noise 成交 → 价格随机游走 → 赚 spread

所以做市定价 = 在 adverse selection 损失 与 spread 收入间找平衡。Kyle 和 Glosten-Milgrom 是两套互补的模型化方法。

维度Kyle (1985)Glosten-Milgrom (1985)
撮合方式Batch auction(一段时间累积订单)逐笔成交(sequential)
informed 行为一次性下连续量 X每次买/卖 1 单位
做市商行为看总流量定价看下一笔方向贝叶斯更新
主要产出线性 price impact Δp = λ · q动态 bid-ask spread
适用场景集合竞价、大宗、隐性流动性连续撮合、CEX 现货、做市报价

二、Kyle (1985) 单期模型严格推导

2.1 设定

  • 资产终值 v ~ N(μ, σ_v²),所有人事前只知 μ 和 σ_v
  • Informed trader (insider):知道 v 的真实值,下连续量 x = β(v − μ),β 待解
  • Noise trader:随机量 u ~ N(0, σ_u²),与 v 独立
  • Market maker (MM):竞争性、风险中性,看到总流量 y = x + u,给出价格 P = E[v | y]
  • 没有 spread(单一价),MM 零利润

2.2 联合正态 → 贝叶斯回归

y = β(v − μ) + u(v, y) 联合正态:

$$ \text{Cov}(v, y) = \text{Cov}(v, \beta v + u) = \beta \sigma_v^2 $$ $$ \text{Var}(y) = \beta^2 \sigma_v^2 + \sigma_u^2 $$

后验均值(线性贝叶斯):

$$ P = E[v | y] = \mu + \frac{\beta \sigma_v^2}{\beta^2 \sigma_v^2 + \sigma_u^2} \cdot y $$

定义市场冲击系数 λ:

$$ \boxed{\lambda = \frac{\beta \sigma_v^2}{\beta^2 \sigma_v^2 + \sigma_u^2}} $$

所以价格规则:P = μ + λ y

2.3 Informed 优化

informed 利润: $$ \pi(x) = (v - P) \cdot x = (v - \mu - \lambda(x + u)) \cdot x $$

informed 不知 u 但知 E[u]=0,所以条件期望: $$ E[\pi | v] = (v - \mu) x - \lambda x^2 $$

一阶条件:(v − μ) − 2λx = 0

$$ \boxed{x^* = \frac{v - \mu}{2 \lambda}, \quad \beta = \frac{1}{2\lambda}} $$

2.4 联立得 λ

代回 λ 表达式:

$$ \lambda = \frac{(1/(2\lambda)) \sigma_v^2}{(1/(2\lambda))^2 \sigma_v^2 + \sigma_u^2} $$

化简:λ · [(1/(4λ²)) σ_v² + σ_u²] = σ_v² / (2λ)

σ_v² / (4λ) + λ σ_u² = σ_v² / (2λ)

λ σ_u² = σ_v² / (2λ) − σ_v² / (4λ) = σ_v² / (4λ)

$$ \boxed{\lambda = \frac{1}{2}\sqrt{\frac{\sigma_v^2}{\sigma_u^2}}} $$

2.5 推论与直觉

公式直觉
informed 头寸x* = (v − μ) σ_u / σ_vinformed 头寸 ∝ noise 量
informed 利润期望E[π*] = σ_v σ_u / 2私有信息越大、噪音越大,越赚
市场效率`Var(vy) = σ_v² / 2`
价格冲击Δp = λ q线性、对称

做市启示

  • 噪音流量 σ_u 越大 → λ 越小 → market deeper → 你做市更安全
  • 信息不对称 σ_v 越大 → λ 越大 → 一笔大单后价格大幅 marche
  • λ 是永久冲击(informational impact),不会回归

Crypto 市场含义:BTC 现货 σ_u 巨大(亿万散户噪音),λ 小;某 micro cap meme coin σ_v 巨大(庄家在暴拉前已知)、σ_u 小,λ 极大——一笔 1 BTC 成交可以推高 5%。

2.6 多期 Kyle (Continuous-time)

Kyle 还推了连续时间版本(Δt → 0),结果惊艳:

  • informed 平滑分配头寸:dx_t = β_t (v − P_t) dt
  • 价格服从布朗桥:dP_t = λ dW_tP_T = v(在 T 时刻信息完全披露)
  • λ 在均匀流量下是常数

直觉:informed 不一次性砸盘,慢慢释放信息,每步泄露同等比例。这就是为什么大单要 VWAP/TWAP 切片执行(Day 83 Almgren-Chriss)。


三、Glosten-Milgrom (1985) 模型

3.1 设定

  • 资产终值 v ∈ {V_H, V_L},先验 P(V_H) = θ
  • 每次到来:以 α 概率是 informed(已知 v)、(1−α) 概率是 noise(50/50 买卖)
  • MM 竞争、零利润、看不到对方类型,只看 buy/sell 方向
  • MM 给出 ask a、bid b,每笔 1 单位

3.2 贝叶斯定价

定义 θ = P(V_H | history)

一笔 buy 到来P(buy | V_H) > P(buy | V_L)

$$ P(\text{buy} | V_H) = \alpha \cdot 1 + (1-\alpha) \cdot 0.5 = \alpha + (1-\alpha)/2 $$ $$ P(\text{buy} | V_L) = (1-\alpha) \cdot 0.5 $$

后验: $$ \theta' = \frac{\theta \cdot P(\text{buy}|V_H)}{\theta P(\text{buy}|V_H) + (1-\theta) P(\text{buy}|V_L)} $$

ask 是 MM 在"卖给某人,但有 α 概率对方知道是 V_H"条件下的零利润价:

$$ a = E[v | \text{trade} = \text{buy}] = \theta' V_H + (1-\theta') V_L $$

类似地 bid 是看到 sell 后的后验期望。

3.3 spread 公式

$$ s = a - b = 2 \alpha (V_H - V_L) \cdot \theta(1-\theta) \cdot \text{(normalizer)} $$

关键性质:

  • spread 反映 informed 概率 α(adverse selection cost)
  • 不确定性最大时(θ=0.5)spread 最大
  • noise/total 越多,spread 越小

Crypto 启示:新币上线 spread 极宽(α 高、信息不对称大),随着信息被吸收 spread 收窄。

3.4 spread 分解(Stoll 1989)

实证 spread 由三部分组成:

  1. Order processing cost (OP) — 撮合系统成本
  2. Inventory holding cost (IH) — 库存暴露成本(明天 A-S 主角)
  3. Adverse selection (AS) — 跟 informed 成交损失(GM 主角)

$$ s = s_{OP} + s_{IH} + s_{AS} $$

CEX BTC 现货:OP ~ 0;IH 由 maker 库存决定;AS 主导 spread。做市报价的本质就是估这三项之和并加 markup


四、代码实现:kyle.py

"""
kyle.py — Kyle (1985) 单期 / Glosten-Milgrom 蒙特卡洛
依赖:numpy, scipy, matplotlib
"""
import numpy as np
from scipy.stats import norm
from dataclasses import dataclass

# ----------------------------------------------------------
# 1. Kyle 单期:解析 + 仿真验证
# ----------------------------------------------------------
@dataclass
class KyleSingle:
    mu: float
    sigma_v: float
    sigma_u: float

    @property
    def lam(self) -> float:
        # λ = (1/2) sqrt(σ_v² / σ_u²)
        return 0.5 * (self.sigma_v / self.sigma_u)

    @property
    def beta(self) -> float:
        return 1.0 / (2 * self.lam)

    def simulate(self, N: int = 100_000, seed=42):
        rng = np.random.default_rng(seed)
        v = rng.normal(self.mu, self.sigma_v, N)
        u = rng.normal(0, self.sigma_u, N)
        x = self.beta * (v - self.mu)
        y = x + u
        P = self.mu + self.lam * y
        # informed 实际利润
        pi = (v - P) * x
        return dict(v=v, u=u, x=x, y=y, P=P, pi=pi)

if __name__ == "__main__":
    k = KyleSingle(mu=100, sigma_v=10, sigma_u=20)
    print(f"理论 λ = {k.lam:.4f}, β = {k.beta:.4f}")
    out = k.simulate(N=200_000)
    # 验证 1:empirical λ via OLS slope of P on y
    emp_lam = np.cov(out["P"], out["y"])[0,1] / np.var(out["y"])
    print(f"经验 λ (OLS) = {emp_lam:.4f}")
    # 验证 2:informed 期望利润 = σ_v σ_u / 2
    print(f"经验 E[π] = {out['pi'].mean():.4f}, "
          f"理论 = {k.sigma_v * k.sigma_u / 2:.4f}")
    # 验证 3:market efficiency Var(v|y) = σ_v²/2
    resid = out["v"] - out["P"]
    print(f"经验 Var(v−P) = {np.var(resid):.4f}, 理论 = {k.sigma_v**2 / 2:.4f}")

预期输出(随机种子下波动 < 1%):

理论 λ = 0.2500, β = 2.0000
经验 λ (OLS) = 0.2503
经验 E[π] = 100.07,  理论 = 100.00
经验 Var(v−P) = 50.12, 理论 = 50.00

完美对应理论。

4.1 多期/动态 Kyle 仿真

def kyle_multi(T=10, N_paths=20000, mu=100, sigma_v=10, sigma_u=20, seed=1):
    """
    Continuous-time approximation: T 期 batch auction
    informed 平滑下单 x_t = β_t (v − P_{t-1}) Δt
    """
    rng = np.random.default_rng(seed)
    dt = 1.0 / T
    v = rng.normal(mu, sigma_v, N_paths)
    P = np.full(N_paths, mu)
    Sigma = sigma_v ** 2          # posterior variance
    paths = np.zeros((N_paths, T+1)); paths[:,0] = mu
    for t in range(T):
        beta_t = np.sqrt(Sigma / (sigma_u**2 * dt))   # equilibrium β_t
        lam_t = 0.5 * np.sqrt(Sigma / (sigma_u**2 * dt))
        x = beta_t * (v - P) * dt
        u = rng.normal(0, sigma_u * np.sqrt(dt), N_paths)
        y = x + u
        P = P + lam_t * y
        # posterior shrinks
        Sigma = Sigma * (1 - 0.5)   # half info revealed each period (approx)
        paths[:, t+1] = P
    return paths, v

# 调用并绘图
import matplotlib.pyplot as plt
paths, v = kyle_multi(T=20, N_paths=5)
plt.figure(figsize=(8,4))
for i in range(5):
    plt.plot(paths[i], alpha=0.6)
    plt.axhline(v[i], linestyle="--", alpha=0.3)
plt.title("Kyle 多期价格收敛于真实 v")
plt.xlabel("Period"); plt.ylabel("Price")
# plt.savefig("kyle_multi.png")

4.2 Glosten-Milgrom 贝叶斯更新

class GMModel:
    """两值资产 V_H/V_L、informed 概率 α、序列 trade 更新"""
    def __init__(self, V_H=110, V_L=90, alpha=0.3, prior=0.5):
        self.V_H, self.V_L, self.alpha = V_H, V_L, alpha
        self.theta = prior   # P(V_H)

    def quote(self):
        """zero-profit ask/bid given current θ"""
        a = self.alpha; t = self.theta
        # P(buy | V_H), P(buy | V_L)
        p_buy_H = a + (1-a) * 0.5
        p_buy_L = (1-a) * 0.5
        p_sell_H = (1-a) * 0.5
        p_sell_L = a + (1-a) * 0.5
        # 后验 if buy
        p_buy = t * p_buy_H + (1-t) * p_buy_L
        theta_buy = t * p_buy_H / p_buy
        # 后验 if sell
        p_sell = t * p_sell_H + (1-t) * p_sell_L
        theta_sell = t * p_sell_H / p_sell
        ask = theta_buy * self.V_H + (1-theta_buy) * self.V_L
        bid = theta_sell * self.V_H + (1-theta_sell) * self.V_L
        return ask, bid

    def update(self, side: str):
        a = self.alpha; t = self.theta
        if side == "buy":
            num = t * (a + (1-a)*0.5)
            den = num + (1-t) * (1-a)*0.5
        else:
            num = t * (1-a)*0.5
            den = num + (1-t) * (a + (1-a)*0.5)
        self.theta = num / den

# 演示
gm = GMModel(V_H=110, V_L=90, alpha=0.3, prior=0.5)
print("Initial spread:")
a, b = gm.quote(); print(f"  ask={a:.3f}, bid={b:.3f}, spread={a-b:.3f}")

# 模拟 5 笔买(似乎是 informed 知道 V_H)
for _ in range(5):
    gm.update("buy")
    a, b = gm.quote()
    print(f"After buy: θ={gm.theta:.3f}, ask={a:.3f}, bid={b:.3f}, spread={a-b:.3f}")

预期输出:

Initial spread: ask=103.000, bid=97.000, spread=6.000
After buy: θ=0.650, ask=104.7, bid=99.3, spread=5.4
After buy: θ=0.778, ask=105.9, bid=101.7, spread=4.2
After buy: θ=0.871, ask=106.7, bid=103.6, spread=3.1
After buy: θ=0.929, ask=107.4, bid=105.0, spread=2.4
After buy: θ=0.962, ask=107.8, bid=106.0, spread=1.8

每笔买都把 θ 推向 1,价格上升、spread 收窄(不确定性减小)。


五、真实数据接入:与 Binance Trade Flow 对比

import requests, pandas as pd

def fetch_binance_trades(symbol="BTCUSDT", limit=500):
    """
    GET /fapi/v1/aggTrades — 聚合成交(买卖标识在 m 字段)
    """
    url = "https://fapi.binance.com/fapi/v1/aggTrades"
    r = requests.get(url, params={"symbol": symbol, "limit": limit}).json()
    df = pd.DataFrame(r)
    df["price"] = df["p"].astype(float)
    df["qty"] = df["q"].astype(float)
    df["time"] = pd.to_datetime(df["T"], unit="ms")
    # m=True 表示 buyer 是 maker → 主动卖
    df["side"] = df["m"].apply(lambda x: "sell" if x else "buy")
    return df[["time", "price", "qty", "side"]]

# 计算 Kyle-style price impact: regress Δprice on signed qty
def empirical_lambda(df, window="1min"):
    df = df.set_index("time")
    df["signed_q"] = df["qty"] * df["side"].map({"buy": 1, "sell": -1})
    grouped = df.resample(window).agg(net_q=("signed_q","sum"),
                                      price=("price", "last"))
    grouped["dp"] = grouped["price"].diff()
    grouped = grouped.dropna()
    # OLS: dp = λ · net_q
    cov = grouped["dp"].cov(grouped["net_q"])
    var = grouped["net_q"].var()
    return cov / var if var > 0 else None

# df = fetch_binance_trades("BTCUSDT", 1000)
# print("Empirical Kyle λ:", empirical_lambda(df))

真实样例响应

// GET /fapi/v1/aggTrades?symbol=BTCUSDT&limit=3
[
  {"a":2451123,"p":"62150.30","q":"0.012","f":4081234,"l":4081234,
   "T":1709337612345,"m":false},
  {"a":2451124,"p":"62150.40","q":"0.085","f":4081235,"l":4081235,
   "T":1709337612456,"m":true},
  {"a":2451125,"p":"62150.40","q":"0.003","f":4081236,"l":4081236,
   "T":1709337612567,"m":false}
]
// m=true → buyer was maker, taker was selling

六、CEX vs DEX 对比

现象CEX (Kyle/GM 显然适用)DEX AMMDEX LOB
价格发现机制Order flow → bayesian updateSwap → reserve 移动类 CEX
谁是做市商显式 MM 看 imbalanceLP 被动显式 MM
adverse selection 体现spread 加宽IL(impermanent loss)= LP 被 informed swap 亏损spread 加宽
价格冲击Δp = λ q 线性Δp = (q/x) (x+q)/x 凸函数类 CEX
信息泄露速度快(流动性高,informed 用大单)受 gas/block time 限制
arbitrageur 角色套利者 = informed 之一套利者就是 LP 主要对手(每个 block 都有 CEX-DEX 套利)套利者

重要观察

  • AMM 上的 IL 在数学上等价于 GM 模型中的 adverse selection cost。LP 是"傻 MM"——只挂 spread=0、永远不更新报价。任何 informed swap 都从 LP 偷走价值。
  • Uni V3 集中流动性可视作允许 LP "选择 spread"——窄区间 → 高 fee 收入但 IL 风险大;宽区间 → 类似 V2。
  • 这就是为什么 V3 LP 业绩高度依赖主动管理(再平衡)。

七、风险与陷阱

  1. Kyle λ 是单期值,不能直接当 5min K 线 impact 用 多个 informed、跨期效应、block-trade carve-outs 都让线性假设失效。crypto 上 informed 经常是单一 whale。

  2. GM 假设 1 单位、对称信息 实盘 informed 调整 size、混入 noise 流——做市商必须维护后验混合分布。

  3. MC 仿真的 numerical λ 漂移 Var(y) → 0 时(例如 σ_u 极小)公式数值不稳。生产代码必须 epsilon clamp。

  4. 把 microprice 当 fair value 用于 large size microprice 只在 "下一笔 1 单位"层面 unbiased。对 size 100 的单子,要用 GM 模型对应的 size 函数 f(q) = E[v | trade size q]

  5. 数据上 Kyle 估计需要 signed flow Binance m 字段是 maker side,要正确反向(taker = aggressor)。错一行符号,估出来的 λ 全反。


八、关键速查

Kyle 单期:
  λ = (1/2) σ_v / σ_u
  β = 1 / (2λ) = σ_u / σ_v
  x* = (v − μ) / (2λ)
  E[π*] = σ_v σ_u / 2
  Var(v|y) = σ_v² / 2     (50% info revealed)

GM 序列:
  ask = E[v | next = buy], bid = E[v | next = sell]
  spread ↑ when α↑ (more informed) or θ→0.5 (more uncertain)
  spread = OP + IH + AS

Empirical λ估计:
  resample signed flow → OLS Δp on net_q

九、面试题

Q1: 请推导 Kyle (1985) 单期模型中 λ 的闭式解。

见上文 §2。关键步骤:(1) 联合正态 → 线性贝叶斯 P=μ+λy;(2) informed 一阶条件得 β=1/(2λ);(3) 代回 λ 表达式联立解 λ=(1/2)σ_v/σ_u

Q2: 在 Crypto 市场 Kyle λ 应用有什么困难?

A: (i) noise volume σ_u 估计困难(whale 假装 noise);(ii) σ_v 在 hype 周期可数量级跳变;(iii) 多 informed 竞争(不只一个 whale 知道)使理论被动;(iv) 跨交易所信息泄露(Binance 大单立即在 Bybit 反映,破坏单交易所闭合假设)。

Q3: Glosten-Milgrom 中如果 α=1(所有人都是 informed),spread 会怎样?

A: spread = V_H − V_L(最大可能 spread);MM 永远亏 / 退出;市场崩溃。"流动性必须依赖 noise" — Black-Milgrom 经典结论。

Q4: 用 GM 解释为什么新币上线 spread 大、几小时后收窄。

A: 新币 θ ≈ 0.5(最大不确定)、α 高(早期参与者多为 informed)。每笔成交以贝叶斯方式压缩 θ 分布、释放信息,spread 随后验集中收窄。这也是为什么"价格发现期" funding rate 异常波动。

Q5: AMM 上的 IL 如何对应 Kyle / GM 中的 adverse selection?

A: AMM LP 没有报价权,spread 永久=0,相当于"被动 MM 永远报 fair price"。任何对池子有信息优势的 swap 都构成 informed flow。LP 损失 = ∫ (v_t − pool_price_t) · Δreserve_t dt,与 GM 中"成交后看到价格 marche"的损失同构。Uni V3 LP 把"集中区间"作为变相的"挂单价",但仍无 spread 选择权——所以才需要 fee 弥补。


明日预告

Day 77:流动性指标 — 把今天的"informed/noise"理论落到三个可测量指标:bid-ask spread、深度(Kyle's depth = 1/λ)、Amihud illiquidity。我们会在 BTC/ETH/SOL 三对上比较,用 Binance 真实分钟数据计算 Amihud |r|/V,证明 Kyle λ ≈ Amihud 是同一指标的两面。