σμ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.4·~55 分上級

アジアンオプション

ロードマップ上の位置モジュール 8/11 · トピック 4/10
8.4 アジアンオプション
—ラボスコア— / 100合計XP—連続日数—

平均価格で支払う

通常のコールは、最終日の1日の価格だけで決まります。アジアンオプションは複数の日付にわたる平均価格で決まり、アジアン・コールは max(平均 - K, 0) を支払います。毎月の原油購入のように継続的に発生するコストのヘッジに企業が使い、満期時の価格操作もしにくい特徴があります。*経路依存*なので算術平均には単純なブラック=ショールズの公式がなく、通常の道具はモンテカルロ・シミュレーションです。

import numpy as np

# Two simulated paths: the starting price, then monthly prices; the last column is expiry
paths = np.array([[100.0, 90.0, 110.0, 130.0],
                  [100.0, 70.0,  80.0,  90.0]])
average = paths[:, 1:].mean(axis=1)                      # the monitoring dates only, not the starting price
print(average)                                           # [110.  80.]
print(np.maximum(average - 100.0, 0.0))                  # Asian call payoffs: [10.  0.]
print(np.maximum(paths[:, -1] - 100.0, 0.0))             # European call payoffs on the same paths: [30.  0.]

経路をシミュレートする

経路は幾何ブラウン運動から作り、ドリフトはリスク中立のものを使います。mu の代わりに金利 r です。経路ごとに1行、観測日ごとに1列の標準正規乱数の行列を引き、対数価格の変化に変換して、各行に沿って累積和を取ります。これで1つの配列にすべての経路が入り、以降の処理(平均、ペイオフ)は行方向のベクトル化された操作1つで、経路に対するループは不要です。

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))
    log_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(log_moves, axis=1)]))

rng = np.random.default_rng(1)
paths = simulate_paths(100.0, 0.05, 0.2, 1.0, 12, 50000, rng)       # monthly monitoring for a year
print(paths.shape)                                                   # (50000, 13)
print(round(float(paths[:, -1].mean()), 2), round(100 * np.exp(0.05), 2))      # the risk-neutral mean of the final price

価格とその誤差

オプションの価格は割引した平均ペイオフ exp(-r * T) * mean(payoffs) です。モンテカルロの価格は推定値なので、必ず標準誤差 std(payoffs) / sqrt(経路数)(割引後)を併記します。数字が真値からどれだけ離れうるかを示し、経路数を4倍にすると半分になります。同じ株のアジアン・コールはヨーロピアン・コールより安く、平均が価格を滑らかにして実効ボラティリティを下げるためです。

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))
    log_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(log_moves, axis=1)]))

def asian_price(paths, strike, rate, t):
    payoff = np.maximum(paths[:, 1:].mean(axis=1) - strike, 0.0)
    discount = np.exp(-rate * t)
    return discount * payoff.mean(), discount * payoff.std(ddof=1) / np.sqrt(len(payoff))

rng = np.random.default_rng(1)
paths = simulate_paths(100.0, 0.05, 0.2, 1.0, 12, 100000, rng)
price, error = asian_price(paths, 100.0, 0.05, 1.0)
european = np.exp(-0.05) * np.maximum(paths[:, -1] - 100.0, 0.0).mean()
print(round(float(price), 3), "+/-", round(float(error), 3))
print(round(float(european), 3), "European call on the same paths")
# Geometric and arithmetic averages of the same monitoring prices
import numpy as np

prices = np.array([90.0, 110.0, 130.0])
arithmetic = prices.mean()
geometric = np.exp(np.log(prices).mean())
print(round(float(arithmetic), 3), round(float(geometric), 3))        # 110.0 108.774: the geometric average is never larger
幾何平均には公式がある対数正規分布の積は対数正規なので、幾何平均に対するアジアン・オプションはブラック=ショールズ型の公式で値付けできます。そのため検算に便利で、さらに算術平均版のコントロール変量として価値があります。2つのペイオフは強く相関するので、幾何版の既知の厳密価格がモンテカルロのノイズの多くを打ち消せます。後のトピック(コントロール変量)がまさにこの考え方を使います。
  • アジアンオプションは観測日の平均で支払う:max(平均 - K, 0)。経路依存で単純な公式はなく、モンテカルロが道具になる
  • 全経路を1つの配列(行=経路、列=日付)にリスク中立ドリフトで作る。平均とペイオフは行方向でベクトル化できる
  • 価格=exp(-r * T) * mean(payoffs)、標準誤差は std / sqrt(paths)。平均化でヨーロピアン・コールより安くなり、幾何版はコントロール変量になる

次はバリアオプションです。価格がある水準に触れると発生または消滅します。

ラボ:採点される内容

  • average_price で各経路の平均を取る25点
  • geometric_average で幾何平均を試す25点
  • asian_call_payoff で平均価格に基づく支払を求める25点
  • asian_price で誤差付きで値付けする25点
エクスプローラー · lab-105-1
▾ lab-105-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-105-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-105-1 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ

コードを実行するにはログインしてください。

レクチャーはすべて無料で読めます。コードの実行、テスト、ラボの提出にはアカウントの作成かログインが必要です。

  • ブラウザ内IDEとbashターミナル。インストール不要
  • 即時採点、XP、ロードマップでの現在地
アカウントを作成ログイン
または
GitHubで続ける