Mímisbrunnr知恵の泉

← 金融工学 一覧

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

📎 前提:時間価値と現在価値・割引金利と複利 | 関連:デュレーションとコンベクシティ

要点(BLUF)

1. 債券価格=割引現在価値

額面 FF、年クーポン率 cc、満期 nn 年の債券は、毎年 FcFc のクーポンを払い、満期に元本 FF を返します。価格はこれらを利回り yy で割り引いた合計です。

P=t=1nFc(1+y)t+F(1+y)nP = \sum_{t=1}^{n}\frac{Fc}{(1+y)^t} + \frac{F}{(1+y)^n}

第1項がクーポンの現在価値(等比数列=年金)、第2項が元本の現在価値です。利回り yy とクーポン率 cc の大小で、価格が額面の上か下かが決まります。

2. 最終利回り(YTM)

**最終利回り(YTM: Yield to Maturity)**は、市場価格 P市場P_{\text{市場}} を上の式に当てはめたとき成り立つ単一の yy です。クーポンを YTM で再投資できると仮定したときの、満期までの実効利回りに相当します。価格と YTM は1対1なので、brentq で逆算できます。

import numpy as np
from scipy.optimize import brentq

def bond_price(face, coupon_rate, ytm, n, freq=1):
    N = n*freq
    c = face*coupon_rate/freq                 # 1回あたりのクーポン
    t = np.arange(1, N+1)
    cf = np.full(N, c, dtype=float)
    cf[-1] += face                            # 満期は元本も返る
    return np.sum(cf/(1 + ytm/freq)**t)

face, coupon_rate, n = 100.0, 0.05, 10        # 額面100, クーポン5%, 10年

for y in [0.03, 0.04, 0.05, 0.06]:
    print(f"YTM={y:.0%}: 価格 {bond_price(face, coupon_rate, y, n):.4f}")

# 価格から YTM を逆算(価格と利回りは1対1)
mkt_price = bond_price(face, coupon_rate, 0.04, n)
ytm = brentq(lambda y: bond_price(face, coupon_rate, y, n) - mkt_price, 0.001, 0.5)
print(f"価格 {mkt_price:.4f} から逆算した YTM = {ytm:.4%}")

出力:

YTM=3%: 価格 117.0604
YTM=4%: 価格 108.1109
YTM=5%: 価格 100.0000
YTM=6%: 価格 92.6399
価格 108.1109 から逆算した YTM = 4.0000%

出力の意味:YTM がクーポン率 5% に等しいとき、価格はちょうど額面 100。YTM がそれより低い(3〜4%)と価格は額面超(プレミアム)、高い(6%)と額面割れ(ディスカウント)。「利回りが下がると価格は上がる」という逆相関が読めます。価格 108.11 から逆算すると YTM = 4.00% がぴたり戻り、価格と利回りが表裏一体だと分かります。これは インプライドボラティリティ の逆算と同じ発想です。

3. スポットレートとイールドカーブ

YTM は「その債券1本の平均的な利回り」ですが、より基礎的なのは各満期ごとの割引率スポットレート(ゼロレート) ztz_t です。満期 tt のスポットレートは、その時点だけのキャッシュフロー(ゼロクーポン債)を割り引く率で、満期ごとに ztz_t を並べたものがイールドカーブ。連続複利なら割引係数は eztte^{-z_t t} です。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib

def bond_price(face, coupon_rate, ytm, n, freq=1):
    N = n*freq
    c = face*coupon_rate/freq
    t = np.arange(1, N+1)
    cf = np.full(N, c, dtype=float); cf[-1] += face
    return np.sum(cf/(1 + ytm/freq)**t)

# 価格・利回り曲線(逆相関・下に凸=コンベクシティ)
ys = np.linspace(0.01, 0.10, 100)
prices = [bond_price(100, 0.05, y, 10) for y in ys]
plt.figure(figsize=(7, 4))
plt.plot(ys*100, prices, lw=2)
plt.axhline(100, color="gray", ls=":", label="額面 100")
plt.scatter([5], [100], color="crimson", zorder=5, label="クーポン=YTM(額面)")
plt.xlabel("最終利回り YTM (%)"); plt.ylabel("債券価格")
plt.title("価格・利回りの関係(逆相関・下に凸)")
plt.legend(); plt.grid(alpha=0.3); plt.tight_layout(); plt.show()

# スポットレート(ゼロレート)→ 割引係数(連続複利)
maturities = np.array([1, 2, 3, 5, 10])
spot_rates = np.array([0.02, 0.025, 0.03, 0.035, 0.04])
discount_factors = np.exp(-spot_rates*maturities)
print("満期      :", maturities)
print("スポット率:", spot_rates)
print("割引係数  :", np.round(discount_factors, 4))

出力:

満期      : [ 1  2  3  5 10]
スポット率: [0.02  0.025 0.03  0.035 0.04 ]
割引係数  : [0.9802 0.9512 0.9139 0.8395 0.6703]

出力の意味:満期が延びるほどスポットレートが上がる(2%→4%)右肩上がりの順イールドで、割引係数は 0.98→0.67 と逓減します。10年後の1円はいまの 0.67 円。このカーブが決まれば、任意の債券は「各クーポン×その満期の割引係数」を足すだけで価格づけできます。市場の債券価格からこのカーブを逆算する作業をブートストラップと呼び、デリバティブ評価の出発点になります(順イールドが普通ですが、景気後退の予兆として逆イールド=右肩下がりが注目されます・要最新確認)。価格・利回り曲線が下に凸である点は、次の デュレーションとコンベクシティ のコンベクシティそのものです。

⚠️ よくある誤解

関連ノート