σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft Academy学习路线
Ctrl K
AO
+1.2k 位学习者
登录加入 ↗
学习路线
AO
+1.2k 位学习者
登录
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python 学习路线›模块 8 · 随机模型与机器学习›主题 8.5·~1小时高级

障碍期权

路线进度模块 8/11 · 主题 5/10
8.5 障碍期权
—实验得分— / 100总 XP—连续天数—

带暗门的期权

障碍期权是带开关的看涨或看跌期权。敲出期权在价格触及障碍时失效;敲入期权只有在触及时才生效。障碍可以在起始价之上(向上)或之下(向下)。由于买方放弃了一部分收益,障碍期权比普通期权便宜,这也是它流行的原因,在结构化产品中尤其如此。和亚式期权一样,它依赖整条路径,自然的工具就是模拟。

import numpy as np

paths = np.array([[100.0, 105.0, 112.0, 108.0],      # stays below 115
                  [100.0,  98.0, 103.0, 110.0],      # stays below 115
                  [100.0, 120.0,  95.0,  90.0]])     # touches 115 on day 1, then falls

hit_up = paths.max(axis=1) >= 115.0                  # the maximum of each path against the barrier
print(hit_up)                                        # [False False  True]
print(paths.min(axis=1) <= 96.0)                     # a down barrier at 96: [False False  True]
# hit_barrier for both directions, with an error for anything else
import numpy as np

def hit_barrier(paths, barrier, direction):
    if direction == "up":
        return paths.max(axis=1) >= barrier
    if direction == "down":
        return paths.min(axis=1) <= barrier
    raise ValueError("direction must be 'up' or 'down'")

paths = np.array([[100.0, 110.0, 105.0], [100.0, 109.9, 105.0]])
print(hit_barrier(paths, 110.0, "up"))                  # [ True False]: touching the barrier exactly counts
try:
    hit_barrier(paths, 110.0, "sideways")
except ValueError as error:
    print("rejected:", error)

敲出、敲入及其和

对每条路径,计算普通看涨期权的收益 max(S_T - K, 0) 以及障碍标志。敲出看涨期权在*未*触及障碍的路径上保留收益;敲入看涨期权在触及的路径上保留收益。每条路径只会是二者之一,所以逐条路径都有*敲入 + 敲出 = 普通看涨*,这是个方便的恒等式:定价较容易的那个就能顺便得到另一个,还可用来检验代码。np.where(hit, a, b) 按元素在两个数组之间选择。

import numpy as np

paths = np.array([[100.0, 105.0, 112.0, 108.0],
                  [100.0,  98.0, 103.0, 110.0],
                  [100.0, 120.0,  95.0, 130.0]])
strike, barrier = 100.0, 115.0

vanilla = np.maximum(paths[:, -1] - strike, 0.0)
hit = paths.max(axis=1) >= barrier
knock_out = np.where(hit, 0.0, vanilla)
knock_in = np.where(hit, vanilla, 0.0)

print(vanilla, knock_out, knock_in)                      # [ 8. 10. 30.] [ 8. 10.  0.] [ 0.  0. 30.]
print(np.allclose(knock_in + knock_out, vanilla))        # True

定价与离散监测偏差

价格仍是折现后的平均收益。但要留意障碍的检验:模拟只在网格日期上看价格,而真实的连续障碍在日期*之间*也会被突破。步数少时,模拟路径常常悄悄越过障碍,导致敲出看涨期权算得太贵、敲入算得太便宜。增加步数可以减小偏差,把障碍平移约 0.5826 * sigma * sqrt(dt) 的修正也可以。

import numpy as np

def simulate_paths(s0, rate, sigma, t, steps, n_paths, rng):
    dt = t / steps
    z = rng.standard_normal((n_paths, steps))
    moves = (rate - 0.5 * sigma ** 2) * dt + sigma * np.sqrt(dt) * z
    return s0 * np.exp(np.hstack([np.zeros((n_paths, 1)), np.cumsum(moves, axis=1)]))

def knock_out_price(paths, strike, barrier, rate, t):
    vanilla = np.maximum(paths[:, -1] - strike, 0.0)
    payoff = np.where(paths.max(axis=1) >= barrier, 0.0, vanilla)
    return float(np.exp(-rate * t) * payoff.mean())

rng = np.random.default_rng(1)
for steps in (12, 52, 252):
    paths = simulate_paths(100.0, 0.05, 0.25, 1.0, steps, 40000, rng)
    print(steps, round(knock_out_price(paths, 100.0, 130.0, 0.05, 1.0), 3))        # the price falls as monitoring gets finer
障碍风险就是跳空风险在障碍附近,障碍期权的 delta 和 gamma 会跳变,价格的微小变动就可能让整个收益开启或关闭。这使得在障碍附近对冲敲出期权很困难,交易台会为此收费。还要留意谁能影响障碍附近的价格:合同会精确规定哪些价格算数(收盘价、交易所成交价),因为操纵市场的诱惑是真实存在的。
  • 只要路径的最大值(向上)或最小值(向下)在任一日期触及障碍就算触碰;敲出触碰即失效,敲入触碰才生效。
  • 逐条路径,敲入 + 敲出 = 普通看涨期权的收益;用 np.where(hit, a, b) 选择;障碍期权比普通期权便宜。
  • 在网格上模拟会漏掉日期之间的穿越,使敲出期权显得太贵:增加步数或平移障碍;留意障碍附近的跳空风险。

下一节:对偶变量,用更少的模拟获得同样的蒙特卡洛精度的办法。

实验:评分内容

  • 用 hit_barrier 检测触碰25 分
  • 用 knock_out_call_payoff 让期权失效25 分
  • 用 knock_in_call_payoff 让期权生效25 分
  • 用 barrier_price 把收益变成价格25 分
资源管理器 · lab-106-1
▾ lab-106-1
…
bash · 浏览器内
learner@quantcraft:~/lab-106-1$
Python 尚未加载PythonLn 1, Col 1Spaces: 4UTF-8

要重置此主题吗?

lab-106-1 中的所有内容将恢复为初始文件,终端也会被清空。你当前的解答将丢失,且无法撤销。

将被重置
  • main.py → 初始代码
  • 终端历史与测试输出
  • 未提交的更改
将被保留
  • 实验最高得分
  • 你的 XP 与连续天数
  • 讲解进度与笔记

登录后即可运行你的代码。

所有讲解均可免费阅读。创建账户或登录后,即可运行代码、运行测试并提交此实验。

  • 浏览器内 IDE 与 bash 终端,无需安装
  • 即时评分、XP 以及你在学习路线中的位置
创建账户登录
或
使用 GitHub 继续