{ "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 }