Skip to content

ポートフォリオ最適化 (凸二次計画 QP) ​

問題クラスソルバー主な APIリンク
凸二次計画問題 (Convex QP)HiGHS (標準)m.continuous(), m.constraint(), c, minimize, dot, QuadExpr

マーコウィッツの平均・分散モデルに基づき、目標期待リターンと投資比率合計(100%)の制約を満たしながら、資産間の共分散行列から計算されるポートフォリオ全体の分散(リスク wTΣww^T \Sigma w)を最小化します。

INTERACTIVE EXAMPLE · 5 ASSETS CONVEX QP (QuadExpr)

ポートフォリオ配分オプティマイザ (Markowitz QP)

目標期待リターンを変更して「▶ 最適化を実行」を押すと、5資産の共分散行列(QuadExpr)からリスク最小の配分比率を計算します。

HiGHS QP · 0.0 ms · 最小分散: 0.00880
ハイテク株
25.0% E[R]=12.0%
全世界株式
30.0% E[R]=8.5%
不動産 REIT
15.0% E[R]=7.0%
金 (ヘッジ)
10.0% E[R]=5.5%
国債
20.0% E[R]=3.5%

WaSHI による実装 ​

typescript
import { Model, QuadExpr, sum, dot, c, minimize } from "@ohtaman/washi";

async function runPortfolioQP() {
  const m = new Model("MarkowitzPortfolio");

  const assets = ["Tech", "Bonds", "RealEstate"];
  const returns = [0.14, 0.04, 0.08];

  // 各資産への投資ウェイト (0.0 〜 1.0)
  const w = m.continuous(assets, { lb: 0, ub: 1 });

  // 1. 予算制約: ウェイト合計 == 1.0 (100%)
  m.constraint(c`${sum(assets, (a) => w[a])} == 1.0`, "budget");

  // 2. 目標リターン制約: 期待リターン >= 8.5%
  const retMap = Object.fromEntries(assets.map((a, i) => [a, returns[i]]));
  m.constraint(c`${dot(retMap, w)} >= 0.085`, "min_return");

  // 3. 共分散行列に基づくリスク(二次式 w^T * Cov * w)の最小化
  const cov = [
    [0.040, 0.002, 0.015],
    [0.002, 0.005, 0.002],
    [0.015, 0.002, 0.025],
  ];

  let risk = new QuadExpr();
  for (let i = 0; i < assets.length; i++) {
    for (let j = 0; j < assets.length; j++) {
      risk = risk.add(w[assets[i]].mul(w[assets[j]]).mul(cov[i][j]));
    }
  }
  m.objective(minimize(risk));

  const status = await m.solve();
  console.log(`Status: ${status}, Minimal Variance: ${m.objectiveValue?.toFixed(6)}`);
  assets.forEach((name) => {
    console.log(`  ${name.padEnd(10)}: ${((w[name].value ?? 0) * 100).toFixed(2)}%`);
  });
}

runPortfolioQP();
Playground で開く →

Released under the MIT License.