プロジェクト — モンテカルロ・シミュレーション

1. プロジェクト:モンテカルロ・シミュレーション

(1) シナリオ

アリスはポートフォリオのリスクを評価する必要があるが、バリュー・アット・リスク(VaR)には閉形式の計算式が存在しない。従来の分散・共分散法は正規分布を前提としているため、テールリスクを著しく過小評価してしまう。そこで彼女はモンテカルロ・シミュレーションを用いて、10万通りの価格推移をモデル化する。

(1) モンテカルロ法

基本概念:多数のランダムなサンプルを用いて、実際の値を近似する。問題が複雑すぎて解析的な解法では対応できない場合、シミュレーションが唯一の手段となる。

PYTHON
import numpy as np

rng = np.random.default_rng(42)

N = 100_000
x = rng.random(N)
y = rng.random(N)
inside = (x2 + y2) <= 1.0
pi_est = 4 * inside.mean()

print(f"Pi estimate: {pi_est:.6f}")
print(f"Actual pi:   {np.pi:.6f}")
print(f"Error:       {abs(pi_est - np.pi):.6f}")

(2) 円周率の推定

PYTHON
print("=== Monte Carlo Estimation of Pi ===\n")

for N in [1_000, 10_000, 100_000, 1_000_000]:
    x = rng.random(N)
    y = rng.random(N)
    inside = (x2 + y2) <= 1.0
    pi_est = 4 * inside.mean()
    error = abs(pi_est - np.pi)
    print(f"N={N:>9,d}  Pi≈{pi_est:.6f}  Error={error:.6f}")

(3) ランダムウォーク

PYTHON
N = 1000
n_sim = 10_000

steps = rng.choice([-1, 1], size=(n_sim, N))
final_pos = steps.sum(axis=1)

print(f"Final position statistics ({n_sim} simulations):")
print(f"  Mean: {final_pos.mean():.2f}  (theory: 0)")
print(f"  Std:  {final_pos.std():.2f}  (theory: {np.sqrt(N):.2f})")
print(f"  Min:  {final_pos.min()}")
print(f"  Max:  {final_pos.max()}")

(4) オプション価格決定論

PYTHON
S0 = 100
K = 105
r = 0.05
sigma = 0.20
T = 1.0

for n_sim in [10_000, 100_000, 1_000_000]:
    z = rng.standard_normal(n_sim)
    ST = S0 * np.exp((r - 0.5 * sigma**2) * T + sigma * np.sqrt(T) * z)

    call_payoff = np.maximum(ST - K, 0)
    put_payoff = np.maximum(K - ST, 0)

    call_price = np.exp(-r * T) * call_payoff.mean()
    put_price = np.exp(-r * T) * put_payoff.mean()
    call_se = np.exp(-r * T) * call_payoff.std() / np.sqrt(n_sim)

    print(f"N={n_sim:>9,d}")
    print(f"  Call: {call_price:.4f} ± {1.96*call_se:.4f}")
    print(f"  Put:  {put_price:.4f}")

(5) ブートストラップ信頼区間

PYTHON
data = rng.exponential(scale=2.0, size=50)
n = len(data)
B = 10_000

idx = rng.integers(0, n, size=(B, n))
boot_samples = data[idx]
boot_means = boot_samples.mean(axis=1)

ci = np.percentile(boot_means, [2.5, 97.5])
print(f"Bootstrap 95% CI for mean: [{ci[0]:.3f}, {ci[1]:.3f}]")
print(f"Sample mean: {data.mean():.3f}")

(1) ▶ サンプル:モンテカルロ法を用いた円周率の推定(難易度 ⭐⭐)

PYTHON
import numpy as np

rng = np.random.default_rng(42)
N = 100_000
x = rng.random(N)
y = rng.random(N)
inside = (x2 + y2) <= 1.0
pi_est = 4 * inside.mean()
print(f"Estimated Pi: {pi_est:.6f}")
print(f"Actual Pi:    {np.pi:.6f}")
print(f"Error:        {abs(pi_est - np.pi):.6f}")

出力:

TEXT
円周率の近似値:3.141920
円周率の実数:    3.141593
エラー: 0.000327

(2) ▶ サンプル:ランダムウォークのシミュレーション(難易度 ⭐⭐)

PYTHON
import numpy as np

rng = np.random.default_rng(42)
n_steps = 1000
n_simulations = 100

# All walks at once using vectorization
steps = rng.choice([-1, 1], size=(n_simulations, n_steps))
positions = np.cumsum(steps, axis=1)

final = positions[:, -1]
print(f"Mean final position: {final.mean():.2f}")
print(f"Std final position:  {final.std():.2f}")
print(f"Min: {final.min()}, Max: {final.max()}")

出力:

TEXT
最終順位(平均):-0.80
標準最終位置:31.72
最小値:-78、最大値:72

(3) ▶ サンプル:ブートストラップ信頼区間(難易度 ⭐⭐⭐)

PYTHON
import numpy as np

rng = np.random.default_rng(42)
data = rng.exponential(scale=2.0, size=50)

n = len(data)
B = 10_000
indices = rng.integers(0, n, size=(B, n))
boot_means = data[indices].mean(axis=1)

ci = np.percentile(boot_means, [2.5, 97.5])
print(f"Sample mean: {data.mean():.3f}")
print(f"95% CI: [{ci[0]:.3f}, {ci[1]:.3f}]")
print(f"CI width: {ci[1] - ci[0]:.3f}")

出力:

TEXT
標本平均:2.165
95%信頼区間:[1.738, 2.644]
CI幅:0.906


❓ よくある質問

Q モンテカルロシミュレーションはいくつ必要ですか?
A 誤差は ∝ 1/√N です。10,000回実行すると誤差は約1%、1,000,000回実行すると約0.1%になります。 金融商品の価格算定では通常100万回、簡易検証では1万回が用いられます。まず少数のサンプルで実行して標準誤差を推定し、その後サンプル数を増やしてください。
Q VaRとCVaRの違いは何ですか?
A VaR(バリュー・アット・リスク)は、αパーセンタイルの損失閾値、つまり「最悪の5%はここから始まる」というものです。 CVaR(条件付きVaR)は、最悪の5%における平均損失です――「事態が悪化した場合、平均してどの程度悪化するのか?」。CVaRは常にVaR以上となります。
Q モンテカルロ法による結果は信頼できるか?
A 2つの注意点がある:(1) 擬似乱数は決定論的である――シードが異なれば結果も異なるため、常に信頼区間を報告すること;(2) モデルの仮定が重要である――GBMの仮定が間違っていれば、100万回のシミュレーションを行っても意味がない。

📖 まとめ

このプロジェクトでは、以下のことを実践しました:


📝 練習問題

  1. 初心者向け(難易度 ⭐):πの近似計算を、1,000,000点を使用するように変更してください。100,000点の場合と比べて、誤差はどのように変化しますか?

  2. 中級(難易度 ⭐⭐):2次元ランダムウォークを実装してください。各ステップでは、4つの方向(上/下/左/右)のいずれかへ移動します。 1,000ステップからなる経路を10,000通りシミュレーションし、原点からの最終距離の平均を計算してください。

  3. 上級(難易度 ⭐⭐⭐):モンテカルロ法を用いて、アジアン・オプション(ペイオフはパス上の平均価格に依存する)の価格を算出せよ。その価格を、同じパラメータを持つヨーロピアン・オプションの価格と比較せよ。アジアン・オプションの方が安くなる理由を説明せよ。

Web-Tutorial.com

Web-Tutorial 技術チーム

複数の開発者によって共同維持されているプログラミングチュートリアルプラットフォーム。各チュートリアルは専門分野の開発者が執筆・レビューしています。正確で信頼性の高いコンテンツを目指しています — 問題を見つけた場合はお知らせください。

100%