Spaces:
Sleeping
Sleeping
File size: 25,957 Bytes
42f8189 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 |
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 債券利率蒙地卡羅模擬教學\n",
"\n",
"本 Jupyter Notebook 旨在教學演示如何使用 Python 進行債券利率的蒙地卡羅模擬。\n",
"程式碼中的變數名稱、公式與註解都對標 'equation.md' 文件,以利於學習與對照。\n",
"\n",
"## 內容包含:\n",
"\n",
"1. **四種利率模型**:\n",
" * **Vasicek 模型**:用於模擬無風險利率 (drf),具有均值回歸特性。\n",
" * **Cox-Ingersoll-Ross (CIR) 模型**:Vasicek 的變體,確保利率為正。\n",
" * **幾何布朗運動 (GBM) 模型**:一個常用於股價的簡化利率模型。\n",
" * **有風險利率模型**:在無風險利率上疊加一個隨機的信用利差。\n",
"2. **債券價格近似計算**:\n",
" * 根據模擬出的利率路徑,使用「修正存續期間」與「價格曲度」來近似計算債券價格的變化。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. 載入所需函式庫\n",
"\n",
"首先,我們載入 `numpy` 用於數值計算,`matplotlib.pyplot` 用於繪圖,以及 `datetime` 用於處理日期。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from datetime import datetime"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. 利率模擬函數\n",
"\n",
"此區塊定義了四種不同的利率模型函數,用於生成未來的利率路徑。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.1 Vasicek 模型\n",
"\n",
"**隨機微分方程 (SDE):** `dr_t = k(θ - r_t)dt + σdW_t`\n",
"\n",
"此模型描述了一個具有「均值回歸」特性的利率。利率 `r_t` 會傾向於回歸到其長期平均水平 `θ`,回歸的速度由 `k` 控制,而 `σ` 則代表其隨機波動的幅度。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def simulate_vasicek(r_0, k, theta, sigma, T, dt, n_simulations, dW_t):\n",
" \"\"\"\n",
" 使用 Vasicek 模型模擬利率路徑。\n",
" \n",
" :param r_0: float, 初始利率 (r_t 在 t=0 的值)。\n",
" :param k: float, 均值回歸速度 (kappa),代表利率回復到長期均值的速度。\n",
" :param theta: float, 長期平均利率或均衡水平 (θ)。\n",
" :param sigma: float, 波動率 (σ),代表利率隨機波動的幅度。\n",
" :param T: float, 總模擬時長(年)。\n",
" :param dt: float, 每個時間步長(年)。\n",
" :param n_simulations: int, 模擬路徑的數量。\n",
" :param dW_t: np.ndarray, 預先生成的維納過程增量 (dW_t),代表隨機衝擊。\n",
" :return: np.ndarray, 模擬的利率路徑。\n",
" \"\"\"\n",
" num_steps = int(T / dt)\n",
" r_paths = np.zeros((n_simulations, num_steps + 1))\n",
" r_paths[:, 0] = r_0\n",
"\n",
" for t in range(1, num_steps + 1):\n",
" r_paths[:, t] = r_paths[:, t-1] + k * (theta - r_paths[:, t-1]) * dt + sigma * dW_t[:, t-1]\n",
" r_paths[:, t] = np.maximum(0.0001, r_paths[:, t]) # 確保利率為正\n",
" \n",
" return r_paths"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.2 Cox-Ingersoll-Ross (CIR) 模型\n",
"\n",
"**隨機微分方程 (SDE):** `dr_t = k(θ - r_t)dt + σ√r_t dW_t`\n",
"\n",
"CIR 模型是 Vasicek 的變體,其主要優點是能確保利率恆為正值(在 `2kθ > σ²` 的條件下)。波動項 `σ√r_t` 表示利率越高,其波動也越大。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def simulate_cir(r_0, k, theta, sigma, T, dt, n_simulations, dW_t):\n",
" \"\"\"\n",
" 使用 Cox-Ingersoll-Ross (CIR) 模型模擬利率路徑。\n",
" \n",
" :param r_0: float, 初始利率。\n",
" :param k: float, 均值回歸速度。\n",
" :param theta: float, 長期平均利率。\n",
" :param sigma: float, 波動率。\n",
" :param T: float, 總模擬時長(年)。\n",
" :param dt: float, 每個時間步長(年)。\n",
" :param n_simulations: int, 模擬路徑的數量。\n",
" :param dW_t: np.ndarray, 預先生成的維納過程增量。\n",
" :return: np.ndarray, 模擬的利率路徑。\n",
" \"\"\"\n",
" num_steps = int(T / dt)\n",
" r_paths = np.zeros((n_simulations, num_steps + 1))\n",
" r_paths[:, 0] = r_0\n",
"\n",
" for t in range(1, num_steps + 1):\n",
" sqrt_r = np.sqrt(np.maximum(0, r_paths[:, t-1]))\n",
" r_paths[:, t] = r_paths[:, t-1] + k * (theta - r_paths[:, t-1]) * dt + sigma * sqrt_r * dW_t[:, t-1]\n",
" r_paths[:, t] = np.maximum(0.0001, r_paths[:, t]) # 再次確保利率為正\n",
" \n",
" return r_paths"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.3 幾何布朗運動 (GBM) 模型\n",
"\n",
"**隨機微分方程 (SDE):** `dr_t = μr_t dt + σr_t dW_t`\n",
"\n",
"GBM 是金融領域中一個非常經典的模型,常用於模擬股價。它假設資產的報酬率服從常態分佈。雖然在利率模擬中不如均值回歸模型常用,但作為一個基礎模型仍有其教學價值。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def simulate_gbm(r_0, mu, sigma, T, dt, n_simulations, dW_t):\n",
" \"\"\"\n",
" 使用幾何布朗運動 (GBM) 模型模擬利率路徑。\n",
" \n",
" :param r_0: float, 初始利率。\n",
" :param mu: float, 長期漂移趨勢。\n",
" :param sigma: float, 年化波動率。\n",
" :param T: float, 總模擬時長(年)。\n",
" :param dt: float, 每個時間步長(年)。\n",
" :param n_simulations: int, 模擬路徑的數量。\n",
" :param dW_t: np.ndarray, 預先生成的維納過程增量。\n",
" :return: np.ndarray, 模擬的利率路徑。\n",
" \"\"\"\n",
" num_steps = int(T / dt)\n",
" r_paths = np.zeros((n_simulations, num_steps + 1))\n",
" r_paths[:, 0] = r_0\n",
"\n",
" for t in range(1, num_steps + 1):\n",
" drift = (mu - 0.5 * sigma**2) * dt\n",
" diffusion = sigma * dW_t[:, t-1]\n",
" r_paths[:, t] = r_paths[:, t-1] * np.exp(drift + diffusion)\n",
" r_paths[:, t] = np.maximum(0.0001, r_paths[:, t]) # 確保利率為正\n",
" \n",
" return r_paths"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2.4 有風險利率模型\n",
"\n",
"**公式:**\n",
"1. `drs_t = drf_t + spread_t`\n",
"2. `d(spread_t) = σ_s dW_s`\n",
"3. `dW_s = ρ * dW_f + √(1 - ρ²) * dZ_t`\n",
"\n",
"此模型在無風險利率 `drf_t` (例如由 Vasicek 模型生成) 的基礎上,疊加一個隨機變動的信用利差 `spread_t`,從而得到有風險利率 `drs_t`。\n",
"\n",
"信用利差的變動 `dW_s` 與無風險利率的變動 `dW_f` 之間存在相關性 `ρ`,這使得模型能更真實地反映市場情況(例如,經濟惡化時,無風險利率可能下降,而信用利差卻會擴大)。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def simulate_risky_rate(drf_paths, dW_f, initial_spread, sigma_s, rho, T, dt, n_simulations):\n",
" \"\"\"\n",
" 模擬有風險利率 (drs),即在無風險利率(drf)上疊加信用利差(spread)。\n",
" \n",
" :param drf_paths: np.ndarray, 已模擬好的無風險利率路徑。\n",
" :param dW_f: np.ndarray, 生成 drf_paths 所使用的隨機衝擊。\n",
" :param initial_spread: float, 初始信用利差。\n",
" :param sigma_s: float, 信用利差的波動率。\n",
" :param rho: float, drf 與 spread 變動之間的相關係數。\n",
" :param T: float, 總模擬時長(年)。\n",
" :param dt: float, 每個時間步長(年)。\n",
" :param n_simulations: int, 模擬路徑的數量。\n",
" :return: tuple (np.ndarray, np.ndarray), 分別為模擬的有風險利率路徑和信用利差路徑。\n",
" \"\"\"\n",
" num_steps = int(T / dt)\n",
" \n",
" # 1. 生成一個獨立的隨機衝擊 dZ_t\n",
" dZ_t = np.random.normal(0, 1, (n_simulations, num_steps)) * np.sqrt(dt)\n",
" \n",
" # 2. 根據相關係數 rho,合成信用利差的隨機衝擊 dW_s\n",
" dW_s = rho * dW_f + np.sqrt(1 - rho**2) * dZ_t\n",
" \n",
" # 3. 模擬信用利差的路徑\n",
" spread_paths = np.zeros((n_simulations, num_steps + 1))\n",
" spread_paths[:, 0] = initial_spread\n",
" for t in range(1, num_steps + 1):\n",
" spread_paths[:, t] = spread_paths[:, t-1] + sigma_s * dW_s[:, t-1]\n",
" spread_paths[:, t] = np.maximum(0.0001, spread_paths[:, t]) # 確保利差為正\n",
" \n",
" # 4. 有風險利率 = 無風險利率 + 信用利差\n",
" drs_paths = drf_paths + spread_paths\n",
" \n",
" return drs_paths, spread_paths"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. 債券價格計算函數\n",
"\n",
"在得到利率路徑後,我們需要一個方法來估算債券價格的變化。這裡我們使用基於「修正存續期間 (Modified Duration)」和「曲度 (Convexity)」的二階泰勒展開式來近似計算。\n",
"\n",
"**近似公式:** `ΔP/P ≈ -D_mod * Δy + (C_mod / 2) * (Δy)²`\n",
"\n",
"其中:\n",
"- `ΔP/P` 是價格的變動百分比。\n",
"- `D_mod` 是修正存續期間,衡量價格對利率變動的敏感度(一階)。\n",
"- `C_mod` 是曲度,用於修正存續期間的線性估計誤差(二階)。\n",
"- `Δy` 是殖利率的變化量,我們在此用模擬的利率 `r` 來替代。\n",
"\n",
"**注意:** 在我們的系統中,資料庫提供的 `convT` 值是 `P * C_mod / 2`,因此我們需要先將其轉換回公式中所需的 `C_mod / 2` 項。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def calculate_price_paths(r_paths, D_mod, convT, initial_price=100.0):\n",
" \"\"\"\n",
" 使用修正存續期間(D_mod)和價格曲度(convT)來近似計算債券價格路徑。\n",
" \n",
" :param r_paths: np.ndarray, 模擬的利率路徑 (y)。\n",
" :param D_mod: float, 債券的修正存續期間 (Modified Duration)。\n",
" :param convT: float, 來自資料庫的價格曲度值 (P * C_mod / 2)。\n",
" :param initial_price: float, 債券的初始價格。\n",
" :return: np.ndarray, 模擬的債券價格路徑。\n",
" \"\"\"\n",
" num_steps = r_paths.shape[1] - 1\n",
" price_paths = np.zeros_like(r_paths)\n",
" price_paths[:, 0] = initial_price\n",
" \n",
" # 從 convT 反解出公式中需要的 (C_mod / 2) 項\n",
" convexity_factor = convT / initial_price\n",
" \n",
" for t in range(1, num_steps + 1):\n",
" delta_y = r_paths[:, t] - r_paths[:, t-1]\n",
" prev_price = price_paths[:, t-1]\n",
" \n",
" # 計算價格變動百分比 (ΔP/P)\n",
" price_change_percentage = -D_mod * delta_y + convexity_factor * (delta_y ** 2)\n",
" \n",
" # 計算新價格 P(t) = P(t-1) * (1 + ΔP/P)\n",
" price_paths[:, t] = prev_price * (1 + price_change_percentage)\n",
" \n",
" return price_paths"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. 主執行區塊\n",
"\n",
"現在我們將前面定義的函數組合起來,進行完整的模擬流程。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.1 設定模擬參數\n",
"\n",
"首先,我們定義債券的基本資料和模擬的通用參數。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 債券基本資料 (此處為範例,實際應用中從資料庫讀取)\n",
"bond_data = {\n",
" 'name': 'CGB10Y',\n",
" 'avgYld': 2.2, # 平均殖利率 (%)\n",
" 'mdurT': 8.9, # 修正存續期間 (D_mod)\n",
" 'convT': 45.5, # 價格曲度 (P * C_mod / 2)\n",
" 'maturity': datetime(2034, 5, 15)\n",
"}\n",
"\n",
"# 模擬通用參數\n",
"n_simulations = 100 # 模擬次數\n",
"dt = 1/252 # 時間步長 (年),假設一年252個交易日\n",
"\n",
"# 計算剩餘到期年限,作為模擬總時長 T\n",
"time_to_maturity = (bond_data['maturity'] - datetime.now()).days / 365.25\n",
"T = max(time_to_maturity, 0.1) # 確保至少模擬一小段時間\n",
"\n",
"num_steps = int(T / dt)\n",
"time_points = np.linspace(0, T, num_steps + 1) # 模擬的時間點數列\n",
"\n",
"# 初始利率 (將百分比轉為小數)\n",
"r_0 = bond_data['avgYld'] / 100.0\n",
"\n",
"print(f\"債券: {bond_data['name']}\")\n",
"print(f\"剩餘到期年限 (T): {T:.2f} 年\")\n",
"print(f\"模擬次數: {n_simulations}\")\n",
"print(f\"時間步長 (dt): {dt:.4f} 年\")\n",
"print(f\"總步數: {num_steps}\")\n",
"print(f\"初始利率 (r_0): {r_0*100:.2f}%\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.2 設定各模型參數\n",
"\n",
"為每個利率模型設定具體的參數值。這些值通常需要透過歷史數據進行校準。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# 1. Vasicek & CIR 模型參數 (將百分比轉為小數)\n",
"k_vasicek = 0.3\n",
"theta_vasicek = 2.2 / 100.0\n",
"sigma_vasicek = 0.5 / 100.0\n",
"\n",
"k_cir = 0.2\n",
"theta_cir = 2.5 / 100.0\n",
"sigma_cir = 0.4 / 100.0\n",
"\n",
"# 2. GBM 模型參數\n",
"mu_r = 0.05 / 100.0\n",
"sigma_r = 0.6 / 100.0\n",
"\n",
"# 3. 有風險利率模型參數\n",
"initial_spread = 0.8 / 100.0\n",
"sigma_s = 0.3 / 100.0\n",
"rho = 0.6"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.3 生成隨機衝擊\n",
"\n",
"為了讓模擬結果可以重現,我們使用 `np.random.seed` 設定隨機種子。然後,為每個需要獨立隨機性的模型預先生成維納過程的增量 `dW_t`。\n",
"\n",
"`dW_t` 是一個服從 `N(0, dt)` 的隨機變數,等價於 `sqrt(dt) * N(0, 1)`。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"np.random.seed(42) # 設定隨機種子以確保結果可重現\n",
"dW_vasicek = np.random.normal(0, 1, (n_simulations, num_steps)) * np.sqrt(dt)\n",
"dW_cir = np.random.normal(0, 1, (n_simulations, num_steps)) * np.sqrt(dt)\n",
"dW_gbm = np.random.normal(0, 1, (n_simulations, num_steps)) * np.sqrt(dt)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4.4 執行模擬\n",
"\n",
"呼叫前面定義的函數,生成利率路徑和對應的債券價格路徑。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print(\"開始執行利率模擬...\")\n",
"# 1. 模擬無風險利率 drf (Vasicek)\n",
"drf_paths = simulate_vasicek(r_0, k_vasicek, theta_vasicek, sigma_vasicek, T, dt, n_simulations, dW_vasicek)\n",
"\n",
"# 2. 模擬有風險利率 drs (在 drf 基礎上增加信用利差)\n",
"drs_paths, spread_paths = simulate_risky_rate(drf_paths, dW_vasicek, initial_spread, sigma_s, rho, T, dt, n_simulations)\n",
"\n",
"# 3. 模擬綜合利率 dr (GBM)\n",
"dr_paths = simulate_gbm(r_0, mu_r, sigma_r, T, dt, n_simulations, dW_gbm)\n",
"\n",
"# 4. 模擬 CIR 利率 dr_cir\n",
"dr_cir_paths = simulate_cir(r_0, k_cir, theta_cir, sigma_cir, T, dt, n_simulations, dW_cir)\n",
"print(\"利率模擬完成。\")\n",
"\n",
"print(\"開始計算債券價格路徑...\")\n",
"# 5. 計算對應的債券價格路徑\n",
"price_drf_paths = calculate_price_paths(drf_paths, bond_data['mdurT'], bond_data['convT'])\n",
"price_drs_paths = calculate_price_paths(drs_paths, bond_data['mdurT'], bond_data['convT'])\n",
"price_dr_paths = calculate_price_paths(dr_paths, bond_data['mdurT'], bond_data['convT'])\n",
"price_dr_cir_paths = calculate_price_paths(dr_cir_paths, bond_data['mdurT'], bond_data['convT'])\n",
"print(\"價格計算完成。\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. 結果可視化\n",
"\n",
"將模擬結果繪製成圖表,以便直觀地理解利率和價格的動態變化。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5.1 設定 Matplotlib 中文顯示\n",
"\n",
"為了讓圖表能正確顯示中文標題和標籤,我們需要設定 Matplotlib 的字體。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"try:\n",
" plt.rcParams['font.sans-serif'] = ['Microsoft JhengHei'] # For Windows\n",
" plt.rcParams['axes.unicode_minus'] = False\n",
"except:\n",
" print(\"未找到 'Microsoft JhengHei' 字體,圖表中的中文可能無法正常顯示。\")\n",
" print(\"您可以嘗試安裝 'Microsoft JhengHei' 或替換為系統中已有的中文字體,例如 'SimHei' (黑體) 或 'KaiTi' (楷體)。\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5.2 利率模擬路徑圖\n",
"\n",
"下圖展示了四種模型生成的前 50 條利率路徑。可以觀察到不同模型的特徵:\n",
"- **Vasicek** 和 **CIR** 顯示出向長期均值回歸的趨勢。\n",
"- **GBM** 則沒有明顯的均值回歸特性,路徑發散較大。\n",
"- **有風險利率** 的路徑整體高於無風險利率,反映了信用利差的存在。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig_rates, axes_rates = plt.subplots(2, 2, figsize=(14, 10), sharex=True)\n",
"fig_rates.suptitle(f'四種利率模型的模擬路徑 (前 {min(50, n_simulations)} 條)', fontsize=16)\n",
"\n",
"axes_rates[0, 0].plot(time_points, drf_paths[:50, :].T * 100, lw=0.5)\n",
"axes_rates[0, 0].set_title('1. 無風險利率 (drf) - Vasicek')\n",
"axes_rates[0, 0].set_ylabel('利率 (%)')\n",
"axes_rates[0, 0].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_rates[0, 1].plot(time_points, drs_paths[:50, :].T * 100, lw=0.5)\n",
"axes_rates[0, 1].set_title('2. 有風險利率 (drs) - Vasicek + Spread')\n",
"axes_rates[0, 1].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_rates[1, 0].plot(time_points, dr_paths[:50, :].T * 100, lw=0.5)\n",
"axes_rates[1, 0].set_title('3. 綜合利率 (dr) - GBM')\n",
"axes_rates[1, 0].set_xlabel('時間 (年)')\n",
"axes_rates[1, 0].set_ylabel('利率 (%)')\n",
"axes_rates[1, 0].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_rates[1, 1].plot(time_points, dr_cir_paths[:50, :].T * 100, lw=0.5)\n",
"axes_rates[1, 1].set_title('4. CIR 利率 (dr_cir)')\n",
"axes_rates[1, 1].set_xlabel('時間 (年)')\n",
"axes_rates[1, 1].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"fig_rates.tight_layout(rect=[0, 0, 1, 0.96])\n",
"plt.savefig(\"tutorial_rate_paths.png\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5.3 債券價格模擬路徑圖\n",
"\n",
"下圖展示了與上述利率路徑相對應的債券價格變化。我們可以看到,當利率上升時,債券價格下降,反之亦然,這符合債券的基本特性。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"fig_prices, axes_prices = plt.subplots(2, 2, figsize=(14, 10), sharex=True, sharey=True)\n",
"fig_prices.suptitle(f'對應的債券價格模擬路徑 (前 {min(50, n_simulations)} 條)', fontsize=16)\n",
"\n",
"axes_prices[0, 0].plot(time_points, price_drf_paths[:50, :].T, lw=0.5)\n",
"axes_prices[0, 0].set_title('基於 drf (Vasicek) 的價格')\n",
"axes_prices[0, 0].set_ylabel('債券價格')\n",
"axes_prices[0, 0].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_prices[0, 1].plot(time_points, price_drs_paths[:50, :].T, lw=0.5)\n",
"axes_prices[0, 1].set_title('基於 drs (Risky) 的價格')\n",
"axes_prices[0, 1].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_prices[1, 0].plot(time_points, price_dr_paths[:50, :].T, lw=0.5)\n",
"axes_prices[1, 0].set_title('基於 dr (GBM) 的價格')\n",
"axes_prices[1, 0].set_xlabel('時間 (年)')\n",
"axes_prices[1, 0].set_ylabel('債券價格')\n",
"axes_prices[1, 0].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"axes_prices[1, 1].plot(time_points, price_dr_cir_paths[:50, :].T, lw=0.5)\n",
"axes_prices[1, 1].set_title('基於 dr_cir (CIR) 的價格')\n",
"axes_prices[1, 1].set_xlabel('時間 (年)')\n",
"axes_prices[1, 1].grid(True, linestyle='--', alpha=0.6)\n",
"\n",
"fig_prices.tight_layout(rect=[0, 0, 1, 0.96])\n",
"plt.savefig(\"tutorial_price_paths.png\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5.4 最終價格分佈圖\n",
"\n",
"此直方圖顯示了在模擬期結束時,所有模擬路徑的最終債券價格分佈。這對於評估風險至關重要,例如計算 VaR (Value at Risk)。\n",
"\n",
"從圖中可以看出,不同利率模型導致的最終價格分佈形狀和範圍有顯著差異。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"plt.figure(figsize=(10, 6))\n",
"plt.hist(price_drf_paths[:, -1], bins=50, alpha=0.7, label='基於 drf (Vasicek)', density=True)\n",
"plt.hist(price_drs_paths[:, -1], bins=50, alpha=0.7, label='基於 drs (Risky)', density=True)\n",
"plt.hist(price_dr_paths[:, -1], bins=50, alpha=0.7, label='基於 dr (GBM)', density=True)\n",
"plt.hist(price_dr_cir_paths[:, -1], bins=50, alpha=0.7, label='基於 dr_cir (CIR)', density=True)\n",
"plt.title('模擬結束時的債券價格分佈')\n",
"plt.xlabel('最終價格')\n",
"plt.ylabel('機率密度')\n",
"plt.legend()\n",
"plt.grid(True, linestyle='--', alpha=0.6)\n",
"plt.savefig(\"tutorial_final_price_dist.png\")\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. 簡單統計分析\n",
"\n",
"最後,我們對兩種較為重要的模型(無風險和有風險)的最終價格進行統計分析,計算其平均值、標準差和 5% 分位數,並估算 95% VaR。\n",
"\n",
"**VaR (Value at Risk)**:在險價值,衡量在給定的信賴水準(此處為 95%)和持有期間內,預期的最大潛在損失。此處的 VaR 是從初始價格 100 計算的損失。"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"final_prices_drf = price_drf_paths[:, -1]\n",
"final_prices_drs = price_drs_paths[:, -1]\n",
"\n",
"print(\"--- 最終價格統計分析 ---\")\n",
"print(f\"模型: 基於 drf (Vasicek)\")\n",
"print(f\" 平均最終價格: {np.mean(final_prices_drf):.4f}\")\n",
"print(f\" 價格標準差: {np.std(final_prices_drf):.4f}\")\n",
"print(f\" 5% 分位數價格: {np.percentile(final_prices_drf, 5):.4f}\")\n",
"print(f\" 95% VaR (從初始價100計算的潛在最大損失): {100 - np.percentile(final_prices_drf, 5):.4f}\")\n",
"\n",
"print(f\"模型: 基於 drs (Risky)\")\n",
"print(f\" 平均最終價格: {np.mean(final_prices_drs):.4f}\")\n",
"print(f\" 價格標準差: {np.std(final_prices_drs):.4f}\")\n",
"print(f\" 5% 分位數價格: {np.percentile(final_prices_drs, 5):.4f}\")\n",
"print(f\" 95% VaR (從初始價100計算的潛在最大損失): {100 - np.percentile(final_prices_drs, 5):.4f}\")\n",
"print(\"------------------------\")"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3 (ipykernel)",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.13"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
|