ポートフォリオ最適化
🔥 Vibe プロンプト
「100万ドルを5銘柄に配分。期待リターンを最大化、リスク<25%。各銘柄に最低5万ドルの投資。」
ポートフォリオ最適化とは?
ポートフォリオ最適化は、資本を資産に配分して期待リターンを最大化しながらリスクを制御する問題です。これは現代ポートフォリオ理論(Markowitz, ノーベル賞1990)の中核です。
| 概念 | 意味 | |------|------| | 期待リターン | 資産リターンの加重平均 | | リスクスコア | 加重リスク(標準偏差または格付け) | | 分散投資 | 1資産に集中しない(最低5%ルール) | | フル投資 | ウェイト合計 = 100% | | 集中制限 | 最大3銘柄 |
PuLPによる実装
import pulp
# 資産データ
assets = ["TSMC", "MTK", "Delta", "Chunghwa", "Fubon"]
expected_return = [0.15, 0.12, 0.10, 0.04, 0.08] # 期待年率リターン
risk = [0.35, 0.30, 0.25, 0.10, 0.20] # リスクスコア
prob = pulp.LpProblem("ポートフォリオ最適化", pulp.LpMaximize)
# 決定変数
weights = {a: pulp.LpVariable(f"weight_{a}", lowBound=0, upBound=1) for a in assets}
selected = {a: pulp.LpVariable(f"select_{a}", cat="Binary") for a in assets}
# 目的: 期待リターン最大化
prob += pulp.lpSum(expected_return[i] * weights[assets[i]] for i in range(len(assets)))
# 制約1: フル投資
prob += pulp.lpSum(weights.values()) == 1
# 制約2: ポートフォリオリスク ≤ 25%
prob += pulp.lpSum(risk[i] * weights[assets[i]] for i in range(len(assets))) <= 0.25
# 制約3: 選択したら最低5%(トークン的ポジション防止)
for a in assets:
prob += weights[a] >= 0.05 * selected[a]
prob += weights[a] <= selected[a]
# 制約4: 最大3銘柄
prob += pulp.lpSum(selected.values()) <= 3
# 求解
prob.solve(pulp.PULP_CBC_CMD(msg=False))
# 結果
print(f"\n{'='*55}")
print(f"ポートフォリオ最適化 — {pulp.LpStatus[prob.status]}")
print(f"{'='*55}")
print(f"期待リターン: {pulp.value(prob.objective)*100:.2f}%")
print(f"\n{'銘柄':<12} {'比率':<10} {'リターン':<10} {'リスク':<10} {'寄与':<10}")
portfolio_risk = 0
for i, a in enumerate(assets):
w = weights[a].value()
if w and w > 0.001:
contr = expected_return[i] * w
portfolio_risk += risk[i] * w
print(f"{a:<12} {w*100:<9.1f}% {expected_return[i]*100:<9.1f}% {risk[i]*100:<9.1f}% {contr*100:<9.2f}%")
print(f"\nポートフォリオリスク: {portfolio_risk*100:.2f}% (上限: 25%) ✅")
print(f"銘柄数: {sum(1 for a in assets if weights[a].value() > 0.001)}")
効率的フロンティア
リスク制限を変えてプロットすると効率的フロンティアが得られます:
import matplotlib.pyplot as plt
risk_limits = [0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40]
returns = []
for max_risk in risk_limits:
p = pulp.LpProblem("PF", pulp.LpMaximize)
w = {a: pulp.LpVariable(f"w_{a}", 0, 1) for a in assets}
s = {a: pulp.LpVariable(f"s_{a}", cat="Binary") for a in assets}
p += pulp.lpSum(expected_return[i] * w[assets[i]] for i in range(len(assets)))
p += pulp.lpSum(w.values()) == 1
p += pulp.lpSum(risk[i] * w[assets[i]] for i in range(len(assets))) <= max_risk
p.solve(pulp.PULP_CBC_CMD(msg=False))
returns.append(pulp.value(p.objective) if p.status == 1 else 0)
plt.plot(risk_limits, returns, 'bo-')
plt.xlabel('リスク制限'); plt.ylabel('期待リターン')
plt.title('効率的フロンティア'); plt.grid(True)
plt.show()
まとめ
| 項目 | 詳細 | |------|------| | 問題 | リスク制御下で資本配分しリターン最大化 | | 変数 | 連続(比率)+ バイナリ(選択) | | 制約 | フル投資、リスク≤25%、最低/最高比率 | | 目的 | 期待リターン最大化 | | 拡張 | 相関、リバランス、取引コスト、ESG制約 |
制約プログラミング完了!🎉
- ✅ ILP基礎 & PuLP
- ✅ スタッフスケジューリング
- ✅ リソース配分
- ✅ サプライチェーン設計
- ✅ ポートフォリオ最適化
- ✅ 効率的フロンティア
Summary
- 現代ポートフォリオ理論 optimizes risk-return tradeoff
- Efficient Frontier shows optimal portfolios
- Constraints can reflect real-world limitations
- Rebalancing periodically maintains target allocation