1979 年鞅定價理論:無套利即是鞅測度#
| 項目 | 內容 |
|---|---|
| 案發時間 | 1979 年(Harrison–Kreps),1981 年(Harrison–Pliska) |
| 案發地點 | 史丹佛大學、西北大學,izheh 通往巴黎 NFLVR |
| 主角 | J. Michael Harrison、David Kreps、Stanley Pliska、Delbaen–Schachermayer(後續) |
| 案件性質 | Black–Scholes 的風險中性只是特例?無套利的終極數學形態為何 |
| 關鍵證物 | 等價鞅測度 EMM, \(C_0 = e^{-rT}E_Q[\Phi]\) ,NFLVR≈EMM |
| 關聯案件 | 1960 年 Girsanov、1973 年 Black–Scholes、1979 年 CRR 二項樹 |
案發現場#
1973 年 Black–Scholes 用對沖 PDE 算出選擇權價格,但數學家並不滿意。PDE 證明依賴連續交易、自融資、光滑解,處處是分析假設。更深的問題是:風險中性測度 \(Q\) 究竟是計算技巧,還是無套利的本質?
1979 年,Harrison 與 Kreps 把案件搬到鞅的法庭。他們問:在一個多期證券市場中,「沒有套利機會」這句白話,精確對應哪個數學陳述?答案震撼:對應存在一個等價機率測度 \(Q\) ,使所有折現價格都是 \(Q\) 鞅。
案發現場的白板上寫著三行。折現價格 \(\tilde S_t = e^{-rt}S_t\) ,等價測度 \(Q \sim P\) ,鞅性 \(E_Q[\tilde S_t \mid \mathcal F_s] = \tilde S_s\) 。三者齊備,則任何可複製衍生品的價格被迫為:
其中 \(\Phi\) 為到期 payoff。這就是鞅定價公式。
偵查過程#
偵查分三步。第一步,Harrison–Kreps(1979)在離散多期模型中證明:無套利蘊含折現價格可用某個鞅測度表示(鞅 Steal 表現定理的金融版)。這是第一基本定理的雛形。
第二步,Harrison–Pliska(1981)把戰場收窄到有限離散時間,引入 CRR 二項樹的語言,證明市場完備等價於鞅測度唯一。這是第二基本定理的雛形:完備市場中每張或有債權皆可複製,價格唯一。
第三步是連續時間的硬仗。直接的「無套利」太弱,會被 doubling strategy 等詭異套利鑽漏洞。Delbaen–Schachermayer 在 1990 年代以 NFLVR(No Free Lunch with Vanishing Risk)補強,證明 NFLVR 等價於存在等價局部鞅測度(ELMM)。案情表如下:
| 定理 | 條件 | 結論 |
|---|---|---|
| 第一基本定理 | NFLVR 成立 | 存在 EMM / ELMM |
| 第二基本定理 | EMM 唯一 | 市場完備,可複製一切 |
| 風險中性定價 | \(Q\) 存在 | \(C_0 = e^{-rT}E_Q[\Phi]\) |
| Girsanov 構造 | Novikov 等條件 | 從 \(P\) 造出 \(Q\) 的兇器 |
偵查的關鍵證人是 CRR 二項樹(Cox–Ross–Rubinstein,1979)。在每步上漲 \(u\) 、下跌 \(d\) 的樹上,風險中性機率有顯式:
以 \(q\) 倒推期望並折現,即得二項價格;當步數趨無窮,樹收斂到 Black–Scholes 公式。學生第一次看見 \(Q\) 不是抽象存在而是 \(q\) 的極限,鞅定價從此不再玄學。
Girsanov 在此案的角色是兇器供應商:把 \(P\) 下的漂移 \(\mu\) 搬成 \(r\) ,造出 \(Q\) 。Novikov 條件不滿足時 EMM 可能不存在,對應市場允許某種套利——數學與經濟在此嚴絲合縫。
結案報告#
結案陳詞:無套利的數學名字叫鞅測度。第一基本定理說 NFLVR 等價於 EMM 存在,第二基本定理說完備等價於 EMM 唯一,而衍生品價格就是 \(Q\) 下的折現期望。
遺產第一層是統一:Black–Scholes 從 PDE 特例升格為鞅定價的推論,利率、波動微笑、跳躍擴散皆可納入同一框架。第二層是計算:二項樹、 Monte Carlo、PDE 三路大軍都只是在算同一個 \(E_Q\) 。第三層是警示:完備市場是童話,實際市場不完備,EMM 不唯一,定價需另選準則(最小熵、最小方差、效用無差異)。
從 1973 的一條公式,到 1979 的一座法庭,再到 1990 年代的 NFLVR 終審,鞅定價用二十年把「公允」二字寫成定理。下一次聽到風險中性,請記得它不是假設,而是無套利逼出來的證人。
證據與工具#
核心證物一:風險中性定價公式, \(E_Q\) 表 \(Q\) 下期望:
核心證物二:鞅性, \(\tilde S_t\) 表折現價格, \(\mathcal F_s\) 表資訊流:
核心證物三:CRR 風險中性機率, \(u\) 表上漲倍數, \(d\) 表下跌倍數:
辦案工具箱:
| 工具 | 用途 | 備註 |
|---|---|---|
| CRR 二項樹倒推 | 從離散看見 \(Q\) | 對應 _code/1979-binomial_crr.py |
| Girsanov 變換 | 連續模型構造 \(Q\) | 漂移 \(\mu \to r\) |
| NFLVR 檢定 | 排除 doubling 詭辯 | 連續時間必備 |
| 完備性判定 | EMM 唯一即完備 | 跳躍模型多半不完備 |
接案提示:實作 CRR 樹為 100 步,觀察其買權價如何收斂至 Black–Scholes 公式, \(q\) 即離散版的風險中性測度。
補充:程式實作#
對應程式#
本節對應程式為 1979-binomial_crr.py 。
理論呼應#
本文核心定價式為 \(C_0 = e^{-rT} E_Q[\Phi(S_T)]\) ,其中 \(Q\) 為等價鞅測度且折現價格滿足 \(E_Q[\tilde S_t \mid \mathcal F_s] = \tilde S_s\) 。 程式實作 CRR 二項樹的風險中性機率 \(q = (e^{rh} - d) / (u - d)\) ,以倒推期望逼近同一 \(E_Q\) 。 當步數 \(N\) 增至 800 時,樹價收斂至 Black–Scholes 封閉解,體現離散鞅測度趨向連續鞅測度的第一基本定理精神。 市場完備時 \(Q\) 唯一,價格亦唯一,此為第二基本定理在本實驗中的數值對照。
執行方式#
在本文所在目錄執行 python3 _code/1979-binomial_crr.py 。
實測輸出#
本次實測以封閉解 10.45058 為基準,測得 50 步樹價為 10.41069,相對誤差為 0.3817%。 200 步樹價為 10.44059,相對誤差為 0.0956%,800 步樹價為 10.44808,相對誤差為 0.0239%。 三檔誤差單調遞減,且 800 步誤差小於 0.5%,通過驗證門檻。
讀者實驗#
可將步數 \(N\) 由 800 改為 1600,再觀察樹價相對誤差是否繼續縮小。
完整程式如下:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""1979 CRR 二項樹(對應 wiki:Cox-Ross-Rubinstein 二項式模型 / 1979 年 CRR 論文)。
參數 S0=K=100, r=0.05, sigma=0.2, T=1(歐式 call)。
u=exp(s*sqrt(dt)), d=1/u, p=(exp(r*dt)-d)/(u-d),向量化倒推。
比較 N=[50,200,800] 相對 BS 封閉解的誤差:要求誤差遞減且 N=800 誤差 < 0.5%。
只用 numpy(常態 CDF 用 math.erf),固定種子,不畫圖。
"""
import numpy as np
import time
from math import erf
t0 = time.time()
SEED = 1979
np.random.seed(SEED)
S0, K, r, sigma, T = 100.0, 100.0, 0.05, 0.2, 1.0
Ns = [50, 200, 800]
_v_erf = np.vectorize(erf)
def ncdf(x):
return 0.5 * (1.0 + _v_erf(x / np.sqrt(2.0)))
d1 = (np.log(S0 / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
C_bs = float(S0 * ncdf(d1) - K * np.exp(-r * T) * ncdf(d2))
def crr_call(N):
dt = T / N
u = np.exp(sigma * np.sqrt(dt))
d = 1.0 / u
p = (np.exp(r * dt) - d) / (u - d)
disc = np.exp(-r * dt)
j = np.arange(N + 1)
ST = S0 * (u ** j) * (d ** (N - j))
V = np.maximum(ST - K, 0.0)
for _ in range(N, 0, -1):
V = disc * (p * V[1:] + (1.0 - p) * V[:-1])
return float(V[0])
prices, rels = [], []
for N in Ns:
c = crr_call(N)
rel = abs(c - C_bs) / C_bs
prices.append(c)
rels.append(rel)
print(f"[crr] N={N:4d} price={c:.5f} BS={C_bs:.5f} relerr={rel:.4%}")
print(f"[crr] elapsed {time.time()-t0:.2f}s")
assert rels[0] > rels[1] > rels[2], f"errors not decreasing: {rels}"
assert rels[2] < 0.005, f"N=800 relerr {rels[2]} exceeds 0.5%"
print(f"VERIFY: crr relerrs={[f'{e:.4%}' for e in rels]} decreasing, N=800<0.5% PASS")