Mímisbrunnr知恵の泉

← 金融工学 一覧

🎓 レベル:標準 | 重要度:A(必須)

📎 前提:ブラックショールズ公式と解釈幾何ブラウン運動による資産価格モデル | 関連:分散減少法

要点(BLUF)

1. モンテカルロ価格づけの考え方

ブラックショールズ公式と解釈 のとおり、オプション価格はリスク中立期待値 erTEQ[payoff]e^{-rT}\mathbb{E}_Q[\text{payoff}] です。期待値は「大量サンプルの平均」で近似できる——これが大数の法則(統計 大数の法則(弱法則・強法則))に基づくモンテカルロの発想です。

価格erT1Mm=1Mpayoff(ST(m)),ST(m)=S0exp ⁣((r12σ2)T+σTZ(m))\text{価格} \approx e^{-rT}\,\frac{1}{M}\sum_{m=1}^{M}\text{payoff}\bigl(S_T^{(m)}\bigr), \qquad S_T^{(m)} = S_0\exp\!\left((r-\tfrac12\sigma^2)T + \sigma\sqrt{T}\,Z^{(m)}\right)

ドリフトを rr(リスク中立)にした GBM で STS_T を生成するのがポイントです。

2. ヨーロピアンコールの価格と信頼区間

満期価格を100万本サンプリングし、ペイオフを平均します。サンプル平均なので標準誤差が付き、信頼区間で精度を表せます。

import numpy as np
from scipy.stats import norm

def bs_call(S, K, r, sigma, T):
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T)/(sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)

rng = np.random.default_rng(0)
S0, K, r, sigma, T = 100.0, 100.0, 0.05, 0.2, 1.0
M = 1000000

Z = rng.normal(size=M)
ST = S0*np.exp((r - 0.5*sigma**2)*T + sigma*np.sqrt(T)*Z)   # リスク中立GBM
disc_payoff = np.exp(-r*T)*np.maximum(ST - K, 0)

price = disc_payoff.mean()
se = disc_payoff.std(ddof=1)/np.sqrt(M)                      # 標準誤差
print(f"MC価格 = {price:.4f}  (95%信頼区間 ±{1.96*se:.4f})")
print(f"BS厳密値 = {bs_call(S0, K, r, sigma, T):.4f}")

出力:

MC価格 = 10.4697  (95%信頼区間 ±0.0289)
BS厳密値 = 10.4506

出力の意味:100万本で MC 価格は 10.4697、95%信頼区間 ±0.0289\pm0.0289。厳密値 10.4506 はこの区間にしっかり収まっています。モンテカルロの価格は点ではなく区間で出る——どれだけ確かかを標準誤差が教えてくれるのが利点です。逆にいえば、小数2桁の精度を出すだけでも100万本級が要り、計算は重め。次にこの「重さ」を収束の観点で見ます。

3. 収束:標準誤差は 1/√M

モンテカルロの標準誤差は、サンプル数 MM に対して σpayoff/M\sigma_{\text{payoff}}/\sqrt{M}。つまり精度を10倍にするにはサンプルを100倍にする必要があります。

import numpy as np

S0, K, r, sigma, T = 100.0, 100.0, 0.05, 0.2, 1.0

print("収束(標準誤差 ∝ 1/√M):")
for m in [1000, 10000, 100000, 1000000]:
    rng = np.random.default_rng(42)
    Z = rng.normal(size=m)
    ST = S0*np.exp((r - 0.5*sigma**2)*T + sigma*np.sqrt(T)*Z)
    disc = np.exp(-r*T)*np.maximum(ST - K, 0)
    print(f"  M={m:>8}: 価格 {disc.mean():.4f}, 標準誤差 {disc.std(ddof=1)/np.sqrt(m):.4f}")

出力:

収束(標準誤差 ∝ 1/√M):
  M=    1000: 価格 9.9120, 標準誤差 0.4483
  M=   10000: 価格 10.3452, 標準誤差 0.1477
  M=  100000: 価格 10.4205, 標準誤差 0.0468
  M= 1000000: 価格 10.4532, 標準誤差 0.0147

出力の意味MM を10倍にするたび、標準誤差はおよそ 1/100.3161/\sqrt{10}\approx0.316 倍(0.448→0.148→0.047→0.015)。価格も厳密値 10.4506 に近づきます。この遅い収束がモンテカルロの弱点で、これを補うのが 分散減少法 です。それでも、有限差分(第6章 有限差分法)が次元の呪いで苦しむ高次元・多資産では、1/M1/\sqrt{M} が次元に依らないモンテカルロが逆転します。

4. 経路依存オプション:アジアン

モンテカルロの本領は、満期だけでなく経路全体に依存するオプションです。代表がアジアン・オプション——満期価格でなく、期間中の平均価格でペイオフが決まります(max(SˉK,0)\max(\bar S - K, 0))。閉形式が無いので数値計算が必須です。日次経路を生成して価格づけします。

import numpy as np
from scipy.stats import norm

def bs_call(S, K, r, sigma, T):
    d1 = (np.log(S/K) + (r + 0.5*sigma**2)*T)/(sigma*np.sqrt(T))
    d2 = d1 - sigma*np.sqrt(T)
    return S*norm.cdf(d1) - K*np.exp(-r*T)*norm.cdf(d2)

rng = np.random.default_rng(1)
S0, K, r, sigma, T = 100.0, 100.0, 0.05, 0.2, 1.0
M, N = 200000, 252
dt = T/N

Z = rng.normal(size=(M, N))
logpaths = np.cumsum((r - 0.5*sigma**2)*dt + sigma*np.sqrt(dt)*Z, axis=1)
S = S0*np.exp(logpaths)              # M本×N日の経路
avg = S.mean(axis=1)                 # 各経路の期間平均価格
asian = np.exp(-r*T)*np.maximum(avg - K, 0)

print(f"アジアンコール = {asian.mean():.4f}")
print(f"参考 ヨーロピアン = {bs_call(S0, K, r, sigma, T):.4f}")

出力:

アジアンコール = 5.8049
参考 ヨーロピアン = 10.4506

出力の意味:アジアンコール 5.80 は、同条件のヨーロピアン 10.45 よりかなり安い。平均をとると価格のばらつきが抑えられ(平均は個々の終値より変動が小さい)、オプションの価値も下がるからです。閉形式が無くても、経路を生成して平均するだけで価格づけできる——これがモンテカルロの汎用性です。バリア・ルックバック・多資産バスケットなども、ペイオフ関数を差し替えるだけで同じ枠組みで扱えます。

⚠️ よくある誤解

関連ノート