Mímisbrunnr知恵の泉

← 金融工学 一覧

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

📎 前提:平均分散分析 | 数理:凸最適化の基礎(機械学習・制約付き最適化)

要点(BLUF)

1. n資産への一般化と最適化問題

平均分散分析 の式 μp=wμ\mu_p=\mathbf{w}^\top\boldsymbol\muσp2=wΣw\sigma_p^2=\mathbf{w}^\top\Sigma\mathbf{w} は資産数 nn がいくつでもそのまま使えます。効率的フロンティアは、**「目標リターン μ\mu^\ast を達成する中で分散が最小の配分」**を μ\mu^\ast を動かしながら集めたものです。これは制約付き最適化問題になります。

minw wΣws.t.wμ=μ,  w1=1\min_{\mathbf{w}}\ \mathbf{w}^\top\Sigma\,\mathbf{w} \quad\text{s.t.}\quad \mathbf{w}^\top\boldsymbol\mu = \mu^\ast,\ \ \mathbf{w}^\top\mathbf{1}=1

目的関数 wΣw\mathbf{w}^\top\Sigma\mathbf{w} は(Σ\Sigma が正定値なら)凸なので、これは凸最適化です(凸最適化の基礎(機械学習))。空売り(持っていない資産を借りて売り、値下がりで買い戻して利益を狙う取引。配分 wiw_i が負になる)を禁止するなら wi0w_i\ge 0 の制約を加えます。とくに最小分散ポートフォリオはリターン制約を外した

wMVP=Σ111Σ11\mathbf{w}_{\text{MVP}} = \frac{\Sigma^{-1}\mathbf{1}}{\mathbf{1}^\top\Sigma^{-1}\mathbf{1}}

という閉じた形で書けます(ラグランジュ未定乗数法=制約付き最適化を「制約に重み(乗数)を付けて目的関数に組み込み、まとめて微分=0で解く」定石、で導けます)。4資産で実際にフロンティアを描きます。

import numpy as np
import matplotlib.pyplot as plt
import japanize_matplotlib
from scipy.optimize import minimize

mu = np.array([0.08, 0.12, 0.15, 0.10])      # 各資産の期待リターン
sig = np.array([0.12, 0.20, 0.25, 0.15])     # 各資産のボラ
corr = np.array([
    [1.00, 0.30, 0.20, 0.40],
    [0.30, 1.00, 0.50, 0.30],
    [0.20, 0.50, 1.00, 0.25],
    [0.40, 0.30, 0.25, 1.00],
])
Sigma = np.outer(sig, sig) * corr            # 共分散行列
n = len(mu)

# ランダムなロングオンリー配分の雲
rng = np.random.default_rng(0)
W = rng.random((5000, n)); W /= W.sum(axis=1, keepdims=True)
rets = W @ mu
vols = np.sqrt(np.einsum("ij,jk,ik->i", W, Sigma, W))

# 効率的フロンティア(目標リターンごとに分散最小化、long-only)
def pvol(w): return np.sqrt(w @ Sigma @ w)
targets = np.linspace(mu.min(), mu.max(), 50)
front_vols = []
for tr in targets:
    cons = [{"type": "eq", "fun": lambda w: w.sum() - 1},
            {"type": "eq", "fun": lambda w, tr=tr: w @ mu - tr}]
    res = minimize(pvol, np.repeat(1/n, n), bounds=[(0, 1)]*n, constraints=cons)
    front_vols.append(res.fun)
front_vols = np.array(front_vols)

# 最小分散ポートフォリオ(解析解、ショート許容)
ones = np.ones(n); Sinv = np.linalg.inv(Sigma)
w_mvp = Sinv @ ones / (ones @ Sinv @ ones)
mvp_ret, mvp_vol = w_mvp @ mu, np.sqrt(w_mvp @ Sigma @ w_mvp)

plt.figure(figsize=(7, 5))
plt.scatter(vols, rets, s=6, alpha=0.3, label="ランダムな配分")
plt.plot(front_vols, targets, "k-", lw=2, label="効率的フロンティア")
plt.scatter(mvp_vol, mvp_ret, color="crimson", zorder=5, label="最小分散ポートフォリオ")
plt.xlabel("リスク(年率ボラ)"); plt.ylabel("期待リターン")
plt.title("効率的フロンティア(4資産)")
plt.legend(); plt.grid(alpha=0.3); plt.tight_layout(); plt.show()

print("MVP 配分:", np.round(w_mvp, 4))
print(f"MVP リターン {mvp_ret:.4%}, ボラ {mvp_vol:.4%}")

出力:

MVP 配分: [0.6001 0.0875 0.0516 0.2607]
MVP リターン 9.2329%, ボラ 10.7047%

4資産の効率的フロンティア。青い点はランダムな配分、黒い曲線が効率的フロンティア、赤い点が最小分散ポートフォリオ。

↑ 上のコードの出力。点の雲(ランダムな配分)はすべて黒い曲線の右側に入り、曲線は「そのリスクで届くリターンの上限」を表す。左端の赤い点が最小分散ポートフォリオ。

出力の意味:ランダムな配分(点の雲)はすべて、フロンティアの曲線より右側(高リスク側)に入ります。フロンティアは「与えられたリスクで到達できるリターンの上限」です。MVP(赤点)はボラ 10.70% で、どの単独資産(最小でも資産Aの12%)より低リスク。フロンティアの MVP より上側だけが「効率的」——下側は同じリスクでわざわざ低リターンを選ぶことになり、誰も選びません。

2. リスクフリー資産と資本市場線

ここにリスクフリー資産(国債など、ボラ 0・確実なリターン RfR_f)を加えると、状況が一変します。リスクフリー資産と任意の危険資産ポートフォリオ PP を混ぜた組合せは、リスク・リターン平面で直線になります(リスクフリーのボラが0だから)。この直線の傾きはシャープレシオ(リスク1単位あたりに得られる超過リターン=「リスクの取り賃の効率」)(μPRf)/σP(\mu_P-R_f)/\sigma_P。傾きが最大になるのは、RfR_f から引いた直線が効率的フロンティアに接するときで、その接点を接点ポートフォリオ、直線を**資本市場線(CML: Capital Market Line)**と呼びます。

μ=Rf+μtanRfσtan接点のシャープレシオσ\mu = R_f + \underbrace{\frac{\mu_{\text{tan}}-R_f}{\sigma_{\text{tan}}}}_{\text{接点のシャープレシオ}}\,\sigma

接点ポートフォリオも閉じた形で求まります(リスクフリー資産があるとき)。

wtan=Σ1(μRf1)1Σ1(μRf1)\mathbf{w}_{\text{tan}} = \frac{\Sigma^{-1}(\boldsymbol\mu - R_f\mathbf{1})}{\mathbf{1}^\top\Sigma^{-1}(\boldsymbol\mu - R_f\mathbf{1})}
import numpy as np

mu = np.array([0.08, 0.12, 0.15, 0.10])
sig = np.array([0.12, 0.20, 0.25, 0.15])
corr = np.array([
    [1.00, 0.30, 0.20, 0.40],
    [0.30, 1.00, 0.50, 0.30],
    [0.20, 0.50, 1.00, 0.25],
    [0.40, 0.30, 0.25, 1.00],
])
Sigma = np.outer(sig, sig) * corr
ones = np.ones(len(mu)); Sinv = np.linalg.inv(Sigma)

rf = 0.03                              # リスクフリー金利
excess = mu - rf*ones
w_tan = Sinv @ excess / (ones @ Sinv @ excess)   # 接点ポートフォリオ

tan_ret = w_tan @ mu
tan_vol = np.sqrt(w_tan @ Sigma @ w_tan)
tan_sharpe = (tan_ret - rf) / tan_vol

print("接点ポートフォリオ 配分:", np.round(w_tan, 4))
print(f"接点 リターン {tan_ret:.4%}, ボラ {tan_vol:.4%}")
print(f"接点 シャープレシオ(=資本市場線の傾き): {tan_sharpe:.4f}")

# --- フロンティアに資本市場線(CML)を重ねて描く ---
import matplotlib.pyplot as plt, japanize_matplotlib
from scipy.optimize import minimize
n = len(mu)
rng = np.random.default_rng(0)
Wc = rng.random((5000, n)); Wc /= Wc.sum(axis=1, keepdims=True)
cloud_r = Wc @ mu
cloud_v = np.sqrt(np.einsum("ij,jk,ik->i", Wc, Sigma, Wc))
targets = np.linspace(mu.min(), mu.max(), 50); front = []
for tr in targets:
    cons = [{"type": "eq", "fun": lambda w: w.sum() - 1},
            {"type": "eq", "fun": lambda w, tr=tr: w @ mu - tr}]
    front.append(minimize(lambda w: np.sqrt(w @ Sigma @ w),
                          np.repeat(1/n, n), bounds=[(0, 1)]*n, constraints=cons).fun)
w_mvp = Sinv @ ones / (ones @ Sinv @ ones)
mvp_r, mvp_v = w_mvp @ mu, np.sqrt(w_mvp @ Sigma @ w_mvp)

plt.figure(figsize=(7, 5))
plt.scatter(cloud_v, cloud_r, s=6, alpha=0.25, color="#9aa6c8")
plt.plot(front, targets, "k-", lw=2, label="効率的フロンティア")
x = np.linspace(0, cloud_v.max()*1.02, 50)
plt.plot(x, rf + tan_sharpe*x, "--", color="crimson", lw=2,
         label=f"資本市場線 CML(傾き {tan_sharpe:.2f})")
plt.scatter(mvp_v, mvp_r, color="#1f77b4", s=70, zorder=5, label="最小分散ポートフォリオ")
plt.scatter(tan_vol, tan_ret, color="crimson", s=120, marker="*", zorder=6, label="接点ポートフォリオ")
plt.scatter(0, rf, color="black", s=45)
plt.annotate("リスクフリー資産 $R_f$", (0, rf), textcoords="offset points", xytext=(8, -14), fontsize=9)
plt.xlabel("リスク(年率ボラ)"); plt.ylabel("期待リターン")
plt.title("効率的フロンティアと資本市場線"); plt.xlim(0, cloud_v.max()*1.05)
plt.legend(loc="lower right", fontsize=8.5); plt.grid(alpha=0.3); plt.tight_layout(); plt.show()

出力:

接点ポートフォリオ 配分: [0.3124 0.151  0.2142 0.3223]
接点 リターン 10.7484%, ボラ 11.9353%
接点 シャープレシオ(=資本市場線の傾き): 0.6492

効率的フロンティアに資本市場線CMLと接点ポートフォリオを重ねた図。

↑ リスクフリー資産 RfR_f(左下の黒点)から引いた赤い破線が資本市場線。フロンティアにちょうど接する点(星)が接点ポートフォリオで、この直線がすべての配分を上から支配する。

出力の意味:接点ポートフォリオは4資産すべてをプラスで保有し(配分はすべて正)、シャープレシオは 0.6492。これが**「危険資産だけで作れる最良の組合せ」**です。投資家は、自分のリスク許容度に応じて「リスクフリーをどれだけ持つか」を変えるだけ——危険資産の中身(接点ポートフォリオ)は誰でも同じになります。

3. 分離定理:誰もが同じ危険資産ポートフォリオを持つ

この「全投資家がリスクフリー資産と同一の接点ポートフォリオの組合せを持つ」という結論を**分離定理(two-fund separation)**と呼びます。リスク回避度の違いは「リスクフリーと接点の比率」だけに現れ、危険資産の構成比は共通です。

flowchart LR
  RF["リスクフリー資産 (国債)"] --> CML["資本市場線 (CML)"]
  TAN["接点ポートフォリオ (危険資産の最適配分)"] --> CML
  CML --> INV["各投資家の最適 = RF と接点の比率を変えるだけ"]

この「みんなが同じ危険資産ポートフォリオを持つ」という発想を、市場全体に当てはめると——接点ポートフォリオは市場ポートフォリオ(市場に存在する全危険資産を、その時価総額の比率で持つ理論上の組合せ)そのものになり、次の CAPMと証券市場線 の出発点になります。

⚠️ よくある誤解

関連ノート