halo 的技术博客

返回

二叉树是期权定价的入门模型,但也是最容易让人误以为”自己已经懂了”的模型。标准 CRR 树的问题藏在最不起眼的地方:它假设每一步”上涨”的概率 p 是一个常数。

结论先放这:因为 p 是常数,标准二叉树定出来的隐含波动率(IV)只能是一条水平线——它装不下任何微笑或斜笑。想用树去还原市场报价,必须把那个”常数 p”换成”随节点位置变化的 p(i,j)”。 这就是 Rubinstein (1994) 与 Derman-Kani (1994) 各自独立提出的隐含二叉树(Implied Binomial Tree, IBT)

我用真实数值把这条闭环跑通了:先由市场微笑 IV(K) = 0.18 + 0.12·tanh(2·(K/S₀−1))(左高右低的典型股票风险厌恶斜笑)反推出终端风险中性密度(RND),再用前向归纳解出 p(i,j)。最终 IBT 定价的期权倒推回 IV,在 K=85/100/115 三档分别是 0.1320 / 0.1752 / 0.2108,与市场输入 0.1450 / 0.1800 / 0.2150 几乎重合(翼部仅有 ~1 个百分点的离散化误差);而固定 p 的 CRR 树把整条微笑压成一条 18% 的平线。附完整 Python 与六类真实陷阱(高阶)。

隐含二叉树(n=4)示意图:每个节点标了价格,连线上标了状态依赖的上移概率 p(i,j)。同一层不同节点的 p 各不相同——这正是它能"被校准"到微笑的关键

一、为什么固定 p 的二叉树装不下微笑#

标准 CRR 树长这样:每步资产价乘以 u(涨)或 d(跌),u = exp(σ√Δt)d = 1/u。风险中性概率

p = (e^{rΔt} − d) / (u − d)        # 常数,与节点位置无关
plaintext

因为 p 是常数,u,d 也是常数,整棵树产生的终端分布就是一个二项对称分布(对数正态近似)。这种分布定出来的所有行权价期权,倒推 IV 必然是平的——因为树里根本没有”哪个价格区间更可能被走到”的自由度。

下面这张对照图说得很清楚:把同一条市场微笑喂给固定 p 的 CRR 树,它反推出的 IV 被压成一条近似 18% 的水平线,左侧真实波动率高达 27%、右侧低到 6%,它一个都还原不了。

对照:固定 p 的 CRR 树只能定出一条平 IV,市场左高右低的斜笑被完全抹平

直觉:市场微笑告诉我们”深处虚值看跌(低 K)更贵 → 左尾更肥、崩盘概率更高”。固定 p 的树对所有价格一视同仁,自然表达不出这种尾部不对称。

二、IBT 的核心思想:先把”终端分布”定下来#

Rubinstein 的聪明之处在于倒因为果

  1. 市场给我们的是整条微笑 IV(K),不是我们该”假设”什么分布。
  2. IV(K) 用 Black-Scholes 算出每个 K 的看涨期权价格 C(K),再用 Breeden-Litzenberger (1978) 定理:
    f_T(K) = e^{rT} · ∂²C/∂K²      # 风险中性终端密度
    plaintext
  3. f_T(K) 离散化、归一化,得到终端风险中性概率 π_T(j)(每个终端节点 j 的权重)。
  4. 这一步就锁定了”树最后该长成什么样”——终端分布已经等于市场隐含的 RND。

剩下的问题只是:怎么设计中间节点的转移概率,使得从根一路走下去,终端分布恰好是 π_T

三、前向归纳:反解出状态依赖的 p(i,j)#

IBT 保留 u,d 固定(几何结构不变),只让转移概率随节点变化p(i,j) 表示”在时刻 i、第 j 个节点,下一步涨到上邻节点的风险中性概率”。

构造分三步(代码里 build_ibt 实现):

第 1 步: 把市场微笑转成离散终端概率 π_T(j)(用节点间距积分,窗口外截断——真实市场远端本就无流动性报价)。

第 2 步(反 CRR 回投): 已知终端 q(n,·) = π_T,用二叉树的守恒关系往回投影,求出每一层的风险中性概率 q(i,·)

q(i+1, j) = p_crr·q(i, j−1) + (1−p_crr)·q(i, j)
# 反解 q(i,·):自底向上扫,q(i,j) = [q(i+1,j) − p_crr·q(i,j−1)] / (1−p_crr)
plaintext

这里 p_crr 只是回投用的”工具人”常数,不进最终树。

第 3 步(前向归纳,Rubinstein 原版): 有了相邻两层的 q,反解 p(i,j)。自顶层 (i,i) 往下扫:顶部节点只能向上,直接定 p(i,i) = q(i+1,i+1)/q(i,i);随后每个 p(i,j−1) 由下邻守恒式解出:

q(i+1, j) = p(i,j−1)·q(i,j−1) + (1−p(i,j))·q(i,j)
⇒ p(i,j−1) = [q(i+1,j) − (1−p(i,j))·q(i,j)] / q(i,j−1)
plaintext

这样造出的树,终端分布精确等于市场 RND(数值偏差精确到 0),而中间每一步的 p(i,j) 随位置变化——把微笑”长”进了树的拓扑里。

四、自洽检验:我放进去的,能收回来#

这是 IBT 最漂亮的地方。我用 n=120 步、ATM vol 20% 的树,把市场微笑跑一遍:

行权价 KIBT 定价反推 IV市场输入 IV偏差
850.13200.1450−0.013
1000.17520.1800−0.0048
1150.21080.2150−0.0042

终端概率与输入 RND 的最大逐点偏差 = 0.00,概率和 = 1.000000。再看一下状态依赖有多强:中间层 i=60p(i,j) 范围是 0.0000 ~ 0.5035,而对应的常数 CRR 值是 0.5035——也就是说,在深度实值/虚值区域,p 被压到接近 0,把概率质量全部”推”向市场 RND 要求的那一侧。

两个图把这件事可视化了:

终端风险中性分布:IBT 还原出的终端分布(点线)与市场 RND(实线)完全重合

自洽检验:用 IBT 给各档期权定价后倒推 IV,与市场输入微笑几乎重合

状态依赖上移概率 p(i,j) 热图:并非常数,随节点位置显著变化

五、完整 Python 实现(核心段)#

下面是从零实现的骨架。完整可运行脚本见文末说明(与配图同目录的 generate_images.py)。

定价时直接用 q[n](终端风险中性分布)给 payoff 加权即可——因为构造上它已经等于市场 RND,所以结果天然还原微笑。这正是 IBT 比”逐层滚动定价”更稳的地方:终端分布是显式目标,不存在累积误差。

六、诚实的六类真实陷阱#

IBT 优雅,但实战里处处是坑,我挑六个最致命的:

  1. 微笑要在流动性窗口内。 远端(K<0.4S₀ 或 K>2.5S₀)市场根本没有报价,IV(K) 外推出来的是幻觉。本文直接截断并把质量归一化到窗口内——但这意味着窗口外的尾部风险 IBT 不承诺还原。
  2. RND 二阶导对报价噪声极敏感。 ∂²C/∂K² 用有限差分,一旦市场报价有 tick 噪声或买卖价错位,密度会炸出负值/尖刺。真实做必须用平滑样条或 SVI 参数化先平滑微笑,再求导。
  3. 微笑套利(calendar/butterfly arbitrage)。 如果输入的 IV(K) 不满足凸性/单调性约束,反推出来的 f_T(K) 会带负密度,向前归纳时 p 越界——必须 clamp 到 [0,1],而 clamp 本身意味着”这棵 IB 树已经在偷改你的市场观点”。
  4. 离散化误差集中在翼部。 看表中 K=85 偏差 −0.013 比 ATM 的 −0.0048 大——步数越少、翼部越薄,信号越被网格吃掉了。n=120 已经不错,要更准得加步数或自适应网格。
  5. 前向归纳的数值稳定性。 当某节点 q(i,j) 接近 0(深虚值区本就无质量),p(i,j−1) 的除法会放大误差。本文用 1e-15 门槛 + clamp 兜底,但更鲁棒要上 Rubinstein 原版的对数节点累计技巧。
  6. IBT 是”插值”不是”外推”。 它完美还原已有报价的行权价,但对从未报过价的极端 K,定价质量取决于你 如何外推 IV(K)——而外推是纯模型假设,不是市场告诉你的。别把 IBT 当预言机。

七、它到底解决了什么#

IBT 不是又一个定价公式,而是一种把”市场隐含分布”可视化的语言

  • 想要”市场到底觉得崩盘概率多大”?看 IBT 的终端 RND(图 ibt_terminal_dist.png),比看一串 IV 数字直观得多。
  • 想要给”没有流动性的奇异期权”(障碍、亚式、回望)定价?在 IBT 上直接 Monte Carlo 或滚动,比硬套常数-vol BS 靠谱。
  • 想要验证某棵二叉树有没有被”正确校准”?跑一遍第 4 节的表,还原误差一目了然。

一句话收尾:二叉树的威力不在 u,d,而在 p。把常数 p 换成状态依赖的 p(i,j),树就从”假设分布”变成了”读取市场”。

完整可运行代码与全部配图生成脚本:src/content/blog/implied-binomial-tree/generate_images.py(同仓库)。运行即复现本文所有数字与五张图。

隐含二叉树:用市场报价反推风险中性转移概率
https://blog.halo26812.eu.org/blog/implied-binomial-tree
Author halo
Published at 2026年7月19日
版权声明 CC BY-NC-SA 4.0
Comment seems to stuck. Try to refresh?✨