Bid, Ask and Transaction Prices — Adverse Selection và Spread
Tác giả: Lawrence R. Glosten, Paul R. Milgrom (1985) Nguồn: Journal of Financial Economics, Vol. 14, No. 1 Tag:
mới:2026-05-16#microstructure#bid-ask-spread#adverse-selection
Nội dung chính (Core Concept)
Trước Glosten-Milgrom, các mô hình bid-ask spread (Demsetz 1968, Stoll 1978) tập trung vào order processing costs và inventory holding costs. Glosten & Milgrom đưa ra cơ chế thứ ba và quan trọng nhất: adverse selection — market maker (MM) đối mặt rủi ro giao dịch với informed traders (người có thông tin riêng về giá trị thực).
Thiết lập mô hình:
- Tài sản có giá trị thực $V$, là random variable với prior $E[V] = \mu_0$.
- Mỗi giai đoạn, một trader đến: xác suất $\pi$ là informed (biết $V$), xác suất $1-\pi$ là noise/liquidity trader (giao dịch ngẫu nhiên).
- MM đặt giá bid $b$ và ask $a$, là competitive zero-profit (Bertrand competition giữa các MM).
Glosten-Milgrom chứng minh giá bid/ask phải là expected value của V có điều kiện theo direction của order:
$$a = E[V \mid \text{buy order}], \quad b = E[V \mid \text{sell order}]$$
Vì buy order là tín hiệu "ai đó biết V cao", $a > \mu_0 > b$. Spread $a - b$ chính là đo lường adverse selection.
Hệ quả quan trọng: giá bid/ask cập nhật Bayesian sau mỗi trade. Một buy order → MM tăng cả bid và ask. Một sell order → giảm cả hai. Điều này tạo ra price discovery thông qua order flow — quá trình information signaling mà Hasbrouck (1991) sau này quantify bằng VAR.
Hai dự đoán testable:
- Spread tăng khi $\pi$ (tỉ lệ informed) tăng, hoặc khi biến động $V$ tăng.
- Giá price-impact trades không đối xứng với buy vs sell trong môi trường information asymmetry.
Ý tưởng chính cho giao dịch (Key Trading Insight)
Đây là bài kinh điển để hiểu thị trường từ góc nhìn market maker và là nền tảng của tất cả mô hình market microstructure hiện đại:
- Spread không phải nhiễu — nó là tín hiệu kinh tế. Spread rộng → uncertainty cao và/hoặc nhiều informed traders. Trade trong thị trường spread rộng → bạn đang trả "premium thông tin".
- Direction của order chứa thông tin: Buy market order ở ask ⇒ MM nghi ngờ informed, sẽ revise price up. Đây là cơ sở của trade signing (Lee-Ready algorithm) và VPIN (Easley-Lopez de Prado-O'Hara 2012).
- PIN (Probability of Informed Trading): Easley et al. ước lượng $\pi$ trực tiếp từ buy/sell counts daily — proxy cho adverse selection risk.
- Implication cho market makers: cần widen spread khi detect informed flow; mô hình Avellaneda-Stoikov (đã có trong thư viện) extends GM bằng inventory control.
Ứng dụng trên VN30F
VN30F không có designated MM nhưng có order book và spread variation:
- Spread regime filter: Tính trung bình rolling spread (ask - bid) trên 20 phút. Khi spread > P90 historical → market đang nhiễu/đang có informed flow → không market-take, chỉ post limit orders.
- Order flow imbalance + spread: Kết hợp OFI (signal hiện có) với spread widening — khi OFI dương mạnh và spread widen → tín hiệu informed buying mạnh, có thể follow một chiều.
- Lee-Ready trade signing: Phân loại từng tick là buy/sell dựa trên relation to midprice → tính buy/sell volume imbalance trong window, dùng làm directional signal.
- Pre-news widening: Spread thường widen trước macro releases (PMI, CPI VN, FOMC). Backtest stand-aside rule trong windows này.
Code minh họa (Python)
import numpy as np
import pandas as pd
def lee_ready_classify(price: pd.Series, bid: pd.Series, ask: pd.Series) -> pd.Series:
"""
Phân loại từng trade là buy (+1), sell (-1), unknown (0).
Quote-based: price >= mid → buy. Tick-test fallback khi == mid.
"""
mid = (bid + ask) / 2
sign = pd.Series(0, index=price.index, dtype=int)
sign[price > mid] = 1
sign[price < mid] = -1
# tick test for sign == 0
last_price = price.shift(1)
sign.loc[(sign == 0) & (price > last_price)] = 1
sign.loc[(sign == 0) & (price < last_price)] = -1
return sign
def spread_regime(bid: pd.Series, ask: pd.Series, lookback: int = 1200) -> pd.Series:
"""Z-score of spread vs rolling history — detect adverse selection windows."""
spread = ask - bid
return (spread - spread.rolling(lookback).mean()) / spread.rolling(lookback).std()
def estimate_pin_simple(trade_sign: pd.Series, window: int = 78) -> pd.Series:
"""
Simple PIN proxy: |buy_count - sell_count| / total_count over window.
True PIN (Easley) requires ML estimation; this is a fast proxy.
"""
buy_count = (trade_sign == 1).rolling(window).sum()
sell_count = (trade_sign == -1).rolling(window).sum()
total = buy_count + sell_count
return (buy_count - sell_count).abs() / total.replace(0, np.nan)
def trade_with_spread_filter(signal: pd.Series, spread_z: pd.Series,
max_z: float = 1.5) -> pd.Series:
"""Mute signal when spread is abnormally wide (adverse selection regime)."""
filtered = signal.copy()
filtered[spread_z > max_z] = 0
return filteredTài liệu tham khảo
- Glosten, L. R., & Milgrom, P. R. (1985). Bid, ask and transaction prices in a specialist market with heterogeneously informed traders. J. of Financial Economics, 14(1), 71-100.
- Easley, D., & O'Hara, M. (1987). Price, trade size, and information in securities markets. J. of Financial Economics, 19(1), 69-90.
- Easley, D., López de Prado, M., & O'Hara, M. (2012). Flow toxicity and liquidity in a high-frequency world. Review of Financial Studies, 25(5), 1457-1493.
- Lee, C. M. C., & Ready, M. J. (1991). Inferring trade direction from intraday data. J. of Finance, 46(2), 733-746.