Skip to content

Options

Black-Scholes 模型: 为了回答 "期权应如何公平定价" 这个问题

假设股票价格 $ S(t) $ 的动力学为:

\[ dS = S ( r \; dt + \sigma \; dW_t ) \\[5pt] \Longrightarrow S(t) = S_0 \exp[ (r - \sigma^2/2) \; t + \sigma W_t ] \quad \text{Ito's calculus} \]

其中 $ r $: 漂移率, $ \sigma $: 波动率, $ dW_t \sim N(\mu=0, \sigma^2=dt) $: 维纳过程 (标准布朗运动)

假设期权价格 $ V(S, t) $, 构建对冲组合

  • 根据 Ito's lemma (相当于带噪声的泰勒展开)
\[ dV = { \partial V \over \partial t } dt + { \partial V \over \partial S } dS + {1\over 2} {\partial^2 V \over \partial S^2} (dS)^2 \\[5pt] (dS)^2 = \sigma^2 S^2 dt + O(dt^2) \\[5pt] \Longrightarrow dV = { \partial V \over \partial t } dt + { \partial V \over \partial S } dS + {1\over 2} \sigma^2 S^2 { \partial^2 V \over \partial S^2 } dt \]
  • 为了消除 \(dS\) (唯一的随机性来源), 做空 \(1\) 份期权, 买入 $ { \partial V \over \partial S } $ 份股票 (Delta Neutral 对冲), 组合价值为
\[ \Pi = -V + { \partial V \over \partial S } S \\[5pt] \Longrightarrow d\Pi = - \left( { \partial V \over \partial t } + {1\over 2} \sigma^2 S^2 { \partial^2 V \over \partial S^2 } \right) dt \]

\(\Pi\) 的收益率等于无风险利率 \(r\)

  • 无套利原理: BS模型应当给出期权最公平的定价
    • 无风险利率 \(r\): 理想中的 银行 借/存 利率
    • 若 $ d\Pi > r\Pi dt $, 可借钱并买入组合 \(\Pi\) 实现无风险收益
    • 若 $ d\Pi < r\Pi dt $, 可卖出组合 \(\Pi\) 并存钱实现无风险收益
    • 仅当 $ d\Pi = r \Pi dt $, 没有无风险套利机会
\[ d\Pi = r \Pi dt \\[5pt] \Longrightarrow - \left( { \partial V \over \partial t } + {1\over 2} \sigma^2 S^2 { \partial^2 V \over \partial S^2 } \right) dt = r (-V + { \partial V \over \partial S } S) dt \\[5pt] \text{Black-Scholes: } \boxed{ { \underbrace{ \partial V \over \partial t }_{ -\Theta } } + {1\over 2} \sigma^2 S^2 { \underbrace{ \partial^2 V \over \partial S^2 }_{ \Gamma } } + rS { \underbrace{ \partial V \over \partial S }_{ \Delta } } -rV = 0 } \\[5pt] \boxed{ \nu := { \partial V \over \partial \sigma } \quad \rho := { \partial V \over \partial r } } \]

方程的解 (仅思路 无过程)

  • 根据期权类型设定边界条件, 通过替换变量转化为热传导方程, 使用积分变换(格林函数法)求解

  • 对于欧式看涨期权:

\[ \boxed{ V(S, t) = S \; N(d_1) - K e^{-r \; T} \; N(d_2) } \\[5pt] d_1 = { \ln(S/K) + (r + \sigma^2 / 2) T \over \sigma \sqrt{ T } } \\[5pt] d_2 = d_1 - \sigma \sqrt{ T } \\[5pt] T := T_0 - t \quad \text{ time left }\\[5pt] N(\cdot) \quad \text{ standard normal CDF } \\[5pt] \boxed{ \Delta = N(d_1) \quad \Gamma = { N'(d_1) \over S \sigma \sqrt{ T } } \quad \nu = S\sqrt{T} N'(d_1) } \\[5pt] \boxed{ \Theta = - { S N'(d_1) \sigma \over 2\sqrt{T} } - r K e^{-r T} N(d_2) } \]

实战题

1. BS 模型计算验证

投资人买进1000张Option, 股价100, 执行价100, 到期日180天, 波动率16%, 一年256天, 利率7%. 假定此Option为Delta Neutral状态. 用python验证BS Model, 求出当股价涨/跌 1% 时, 一日Theta, 总PL.

  • 结果
stock: 100 -> 99.0
option: 7.968044763858842 -> 7.284780019739209
stock_pl: 667.8328836634573
option_pl: -683.264744119633
Theta_pl + Delta_pl (-stock_pl) + Gamma_pl: -683.9151768360123
    Theta_pl: -29.6140665687756
    Gamma_pl: 13.531773396220588
total_pl: -15.431860456175627


stock: 100 -> 101.0
option: 7.968044763858842 -> 8.619186079616412
stock_pl: -667.8328836634573
option_pl: 651.1413157575703
Theta_pl + Delta_pl (-stock_pl) + Gamma_pl: 651.7505904909024
    Theta_pl: -29.6140665687756
    Gamma_pl: 13.531773396220588
total_pl: -16.69156790588704
  • 代码
from numpy import exp, log, sqrt
from scipy.stats import norm


def bs_euro_call(S, K, r, sig, T):
    cdf, pdf = norm.cdf, norm.pdf

    A = sig * sqrt(T)
    d1 = (log(S / K) + (r + sig**2 / 2) * T) / A
    d2 = d1 - A
    B = K * exp(-r * T) * cdf(d2)

    V = S * cdf(d1) - B
    Delta = cdf(d1)
    Gamma = pdf(d1) / (S * A)
    Theta = -(S * pdf(d1) * sig) / (2 * sqrt(T)) - r * B
    Vega = S * sqrt(T) * pdf(d1)
    return dict(V=V, Delta=Delta, Gamma=Gamma, Theta=Theta, Vega=Vega)


def delta_neutral_step(
    S1,
    T1,
    S2,
    T2,
    K=100,
    r=0.07,
    sig=0.16,
    n_option=1000,
):
    x1 = bs_euro_call(S1, K, r, sig, T1)
    n_stock = -x1["Delta"] * n_option
    x2 = bs_euro_call(S2, K, r, sig, T2)
    Gamma_pl = n_option * 0.5 * x1["Gamma"] * (S2 - S1) ** 2
    Theta_pl = n_option * x1["Theta"] * (T1 - T2)
    stock_pl = n_stock * (S2 - S1)
    option_pl = n_option * (x2["V"] - x1["V"])
    total_pl = stock_pl + option_pl
    info = f"""
stock: {S1} -> {S2}
option: {x1['V']} -> {x2['V']}
stock_pl: {stock_pl}
option_pl: {option_pl}
Theta_pl + Delta_pl (-stock_pl) + Gamma_pl: {Theta_pl - stock_pl + Gamma_pl}
    Theta_pl: {Theta_pl}
    Gamma_pl: {Gamma_pl}
total_pl: {total_pl}
"""
    return dict(
        S=S1,
        V=x1["V"],
        n_stock=n_stock,
        Gamma_pl=Gamma_pl,
        Theta_pl=Theta_pl,
        stock_pl=stock_pl,
        option_pl=option_pl,
        total_pl=total_pl,
        info=info,
    )


if __name__ == "__main__":
    S1, T1, T2 = 100, 180 / 256, (180 - 1) / 256
    for change in [-0.01, 0.01]:
        S2 = S1 * (1 + change)
        res = delta_neutral_step(S1, T1, S2, T2)
        print(res["info"])

2a. 计算股价布朗运动的两种方法

  • 结果

  • 代码
import matplotlib.pyplot as plt
import numpy as np


def stock_price1(S0, num, dt, r, sig):
    S = np.zeros(num)
    S[0] = S0
    dW = np.random.normal(0, np.sqrt(dt), num)
    for i in range(1, num):
        dS = S[i - 1] * (r * dt + sig * dW[i])
        S[i] = S[i - 1] + dS
    return S


def stock_price2(S0, num, dt, r, sig):
    t = np.arange(num) * dt
    dW = np.random.normal(0, np.sqrt(dt), num)
    dW[0] = 0
    return S0 * np.exp((r - sig**2 / 2) * t + sig * np.cumsum(dW))


if __name__ == "__main__":
    S0, num, dt, r, sig = 1, 100, 0.01, 0.1, 0.1
    np.random.seed(0)
    S1 = stock_price1(S0, num, dt, r, sig)
    np.random.seed(0)
    S2 = stock_price2(S0, num, dt, r, sig)
    plt.plot(S1, label="S1")
    plt.plot(S2, label="S2")
    plt.legend()
    plt.savefig("question2a")

2b. 动态 Delta 对冲

股价100, 执行价100, 到期日180天, 波动率16%, 一年360天, 利率7%, 买入1000张Option, 避险频率为1天。用python模拟BS Model下Option的Dynamic Delta Hedge过程.

  • 结果1: 单次模拟

    • excel 文件
    • S: 股票价格, 由 几何布朗运动 生成
    • V: 期权价格 (欧式看涨), 由股票价格以及 BS 公式算出
    • n_stock: (做空) 对冲的股票数量 (由于买入了欧式看涨期权)
    • Gamma_pl: \(\Gamma\) 效应的每日收益
    • Theta_pl: \(\Theta\) 效应的每日收益
    • stock_pl: 每日股票价格变化带来的收益
    • option_pl: 每日期权价格变化带来的收益
    • total_pl: 每日总收益 total_pl = stock_pl + option_pl
      • 可以看出, 这一项绝对值远小于股票/期权收益的绝对值, 体现了对冲
    • cum_total_pl: 累计总收益 cum_total_pl = cumsum(total_pl)
  • 结果2: 多次模拟, 不考虑期权每日收益, 而是看期权的最终执行

股票对冲累计收益: -13177.827686668968
买入期权的成本: -6363.485217326122
期权到期执行带来的收益: 16783.48316247069
最终总收益: -2757.8297415244015

股票对冲累计收益: -10509.726762807535
买入期权的成本: -6363.485217326122
期权到期执行带来的收益: 13973.358289900432
最终总收益: -2899.853690233227

股票对冲累计收益: 4262.71837293126
买入期权的成本: -6363.485217326122
期权到期执行带来的收益: 1694.855159339852
最终总收益: -405.91168505501037

股票对冲累计收益: 5525.898204087093
买入期权的成本: -6363.485217326122
期权到期执行带来的收益: 0
最终总收益: -837.5870132390291

股票对冲累计收益: -8050.688607611437
买入期权的成本: -6363.485217326122
期权到期执行带来的收益: 11540.995496282576
最终总收益: -2873.1783286549835
  • 代码
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from question1 import delta_neutral_step
from question2a import stock_price2


def dynamic_delta_hedging(
    S0=100,
    days=180,
    DAYS=360,
    K=100,
    r=0.07,
    sig=0.16,
    n_option=1000,
):
    dt = 1 / DAYS
    S = stock_price2(S0, days, dt, r, sig)
    results = []
    for i in range(days - 1):
        S1, S2 = S[i], S[i + 1]
        T1 = (days - i) / DAYS
        T2 = (days - (i + 1)) / DAYS
        x = delta_neutral_step(S1, T1, S2, T2, K, r, sig, n_option)
        results.append(x)
    df = pd.DataFrame(results).select_dtypes(include=["number"])
    df["cum_total_pl"] = df["total_pl"].cumsum()
    df["cum_stock_pl"] = df["stock_pl"].cumsum()
    R, C = df.shape
    df.plot(subplots=True, figsize=(6, 3 * C))
    plt.tight_layout()
    plt.savefig("question2b")
    df.to_excel("dynamic_delta_hedging.xlsx", index=False)

    stock_pl2 = df["stock_pl"].sum()
    option_pl0 = -df["V"].iat[0] * n_option
    option_pl2 = max(S[-1] - K, 0) * n_option
    final_pl = stock_pl2 + option_pl0 + option_pl2
    print(f"股票对冲累计收益: {stock_pl2}")
    print(f"买入期权的成本: {option_pl0}")
    print(f"期权到期执行带来的收益: {option_pl2}")
    print(f"最终总收益: {final_pl}")


if __name__ == "__main__":
    for seed in range(5):
        np.random.seed(seed)
        dynamic_delta_hedging()
        print()

3、4. Greeks与 \(\sigma, T\) 的关系

\(\sigma , T\) 与Greeks, 呈何种关系? (用公式说明)

  • 结果: 由以下公式可以看出它们的关系, 比起定性描述, 我认为直接画图直观理解更合理. \(\sigma\) 左图, \(T\) 右图
\[ \boxed{ V(S, t) = S \; N(d_1) - K e^{-r \; T} \; N(d_2) } \\[5pt] d_1 = { \ln(S/K) + (r + \sigma^2 / 2) T \over \sigma \sqrt{ T } } \\[5pt] d_2 = d_1 - \sigma \sqrt{ T } \\[5pt] T := T_0 - t \quad \text{ time left }\\[5pt] N(\cdot) \quad \text{ standard normal CDF } \\[5pt] \boxed{ \Delta = N(d_1) \quad \Gamma = { N'(d_1) \over S \sigma \sqrt{ T } } \quad \nu = S\sqrt{T} N'(d_1) } \\[5pt] \boxed{ \Theta = - { S N'(d_1) \sigma \over 2\sqrt{T} } - r K e^{-r T} N(d_2) } \]
  • 代码
import matplotlib.pyplot as plt
import numpy as np

from question1 import bs_euro_call


def greeks_vs_sigma():
    K, r, T = 100, 0.07, 0.5
    sig_arr = np.linspace(0.01, 0.3, 100)
    keys = ["Delta", "Gamma", "Vega", "Theta"]
    plt.figure(figsize=(6, 3 * len(keys)))
    for i, k in enumerate(keys):
        plt.subplot(len(keys), 1, i + 1)
        plt.title(f"{k} VS sigma")
        for ratio in [0.8, 1, 1.2]:
            S = ratio * K
            Y = [bs_euro_call(S, K, r, sig, T)[k] for sig in sig_arr]
            plt.plot(sig_arr, Y, label=f"S = {ratio} * K")
        plt.legend()
    plt.tight_layout()
    plt.savefig("question3")


def greeks_vs_T():
    K, r, sig = 100, 0.07, 0.16
    T_arr = np.linspace(0.01, 1, 100)
    keys = ["Delta", "Gamma", "Vega", "Theta"]
    plt.figure(figsize=(6, 3 * len(keys)))
    for i, k in enumerate(keys):
        plt.subplot(len(keys), 1, i + 1)
        plt.title(f"{k} VS T")
        for ratio in [0.8, 1, 1.2]:
            S = ratio * K
            Y = [bs_euro_call(S, K, r, sig, T)[k] for T in T_arr]
            plt.plot(T_arr, Y, label=f"S = {ratio} * K")
        plt.legend()
    plt.tight_layout()
    plt.savefig("question4")


if __name__ == "__main__":
    greeks_vs_sigma()
    greeks_vs_T()

5. 波动率微笑

产生Volatility Smile的原因有哪些?

  • 结果
    • 首先根据真实数据画图理解 Volatility Smile, 并进行了 SVI (Stochastic Volatility Inspired) 模型拟合
    • Black-Scholes 假设缺陷
      • BS模型假设波动率 $ \sigma $ 为常数,但实际市场中:
        • 极端价格运动(肥尾:真实资产回报分布呈现肥尾(如崩盘/暴涨),BS对数正态假设低估尾部风险 → 深度实值/虚值期权需更高 $ \sigma $ 定价。
        • 跳跃风险:资产价格存在突发跳跃(如财报发布、黑天鹅事件),连续扩散假设失效 → 虚值期权隐含波动率上升。
    • 市场供需动态
      • 恐慌不对称性:投资者对下跌恐慌(虚值看跌期权需求激增)> 上涨投机(虚值看涨),推高OTM Put的隐含波动率。
      • 对冲压力:做市商对冲OTM期权需动态调整头寸,放大市场波动,反哺 $ \sigma $。
    • 流动性分层
      • 深度实值/虚值期权流动性差 → 买卖价差扩大 → 通过BS公式反推 $ \sigma $ 时人为抬高。
    • 总结
      • 模型缺陷(肥尾/跳跃)→ 市场行为(恐慌/对冲)→ 流动性反馈 → 隐含波动率曲线扭曲为Smile。

  • 代码
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import yfinance as yf
from scipy.optimize import minimize


def SVI(K, params):
    a, b, rho, m, sigma = params
    dK = K - m
    return a + b * (rho * dK + np.sqrt(dK**2 + sigma**2))


def find_SVI_params(K, IV):
    def obj(x):
        return np.sum((SVI(K, x) - IV) ** 2)

    x0 = [0.1, 0.1, -0.5, 0.0, 0.1]
    bounds = [(0, None), (0, None), (-1, 1), (None, None), (0.01, None)]
    return minimize(obj, x0, bounds=bounds).x


def get_option_data(ticker="TSLA", n_expiry=2):
    x = yf.Ticker(ticker)
    for date in x.options[:n_expiry]:
        df: pd.DataFrame = x.option_chain(date).calls
        K = df["strike"]
        IV = df["impliedVolatility"]
        params = find_SVI_params(K, IV)
        sig = SVI(K, params)
        plt.plot(K, IV, label=f"expire: {date}")
        plt.plot(K, sig, label=f"expire: {date} (SVI)")
    plt.title(f"Volatility smile of {ticker}")
    plt.xlabel("K")
    plt.ylabel("implied sigma")
    plt.legend()
    plt.savefig("question5")


if __name__ == "__main__":
    get_option_data()

6. BS模型的基本理解

假设Option的定价波动率35%, 无风险利率3%, 到期时已实现的波动率亦为35%, 则在BS的假设下复制Option, 求此投资组合的报酬率。(请写出具体证明公式)

  • 结果
    • 报酬率 = 无风险利率 = 3%
    • 在本页最上面的 BS 理论推导中, $ d\Pi = r \Pi dt $ 是 BS 定价理论的基本假设/要求, 无需证明.

7. Delta Neutral 的风险

投资人卖出Option 并采取Delta Neutral策略, 可能有哪些因素导致其风险无法完全对冲?

  • 结果
    • Gamma风险: Delta随标的资产价格非线性变化(二阶效应),快速波动时对冲滞后。
    • Vega风险: 隐含波动率变化影响期权价值,Delta对冲不覆盖此风险。
    • 时间衰减(Theta): 时间流逝对期权卖方有利,但需动态调整对冲频率与成本平衡。
    • 流动性风险: 标的资产或期权流动性不足导致无法及时调整头寸。
    • 跳空缺口: 价格不连续变动(如财报发布)使瞬时Delta失效。
    • 利率与股息变化: 影响期权定价因子,尤其对长期期权显著。
    • 交易成本: 频繁调仓损耗利润,降低对冲精度。
    • 相关性风险(组合对冲时): 对冲资产与标的实际相关性偏离预期。
    • 核心矛盾:Delta仅为一阶近似,而市场是多因子动态系统。

8. 看涨 vs 看跌

大部分市场中, Call的隐含波动率通常较Put低, 原因可能是?

  • 结果
    • 需求失衡:市场参与者更倾向于购买Put对冲下行风险,推高Put溢价(隐含波动率上升)。Call的买方(投机者)可能因成本敏感而压低需求。
    • 杠杆偏好:投机者更倾向直接买股票或期货(而非Call)获取杠杆,减少Call的波动率溢价。
    • 市场情绪:恐慌情绪(如尾部风险担忧)对Put的需求影响更不对称。
    • 卖压差异:做市商卖出Call时对冲成本更低(如通过持有正股),导致Call供给弹性更大。
    • 隐含波动率差异本质反映供需不平衡,而非模型本身特性

9. 期货 vs 期权

明天为标的期货结算日, 投资人预期该标的将涨2%, 为使报酬率最大, 会选择期货还是期权?

  • 结果
    • 对可能的情况进行画图
    • 为了最大化收益, 应选择options, 因为options杠杆更大 (但潜在风险也更大)

  • 代码
import matplotlib.pyplot as plt
import numpy as np


def futures_vs_options(
    S0=100,  # 当前标的资产价格
    K=102,  # 虚值看涨期权行权价(预期涨2%)
    margin_ratio=0.12,  # 期货保证金比例(12%)
    V=0.5,  # 虚值期权权利金(0.5% of S0)
):
    # 标的结算价范围:-5%到+5%
    S = S0 * (1 + np.linspace(-0.05, 0.05, 100))

    futures_pl = (S - S0) / (margin_ratio * S0)
    option_pl = (np.maximum(S - K, 0) - V) / V

    plt.plot(S, futures_pl, label="futures pl")
    plt.plot(S, option_pl, label="options pl")
    plt.axvline(K, linestyle="--", label="K=102")
    plt.xlabel("S")
    plt.ylabel("PnL")
    plt.title("futures vs options")
    plt.legend()
    plt.savefig("question9")


if __name__ == "__main__":
    futures_vs_options()