mcpField
P
portfolio-optimization

portfolio-optimization

github.com/nvidiaデータ・データベース3.8k110 回インストール今日更新
リポジトリ

portfolio-optimization について

`portfolio_optimization` と NVIDIA cuOpt を使い、定量ポートフォリオの構築、分析、バックテスト、リバランスを行うスキルです。Mean-CVaR と Mean-Variance の配分に対応し、GPU最適化や効率的フロンティアの作成を扱います。

主な機能

  1. 01Mean-CVaRポートフォリオ最適化
  2. 02Mean-Variance SOCP配分
  3. 03GPU KDEシナリオ生成
  4. 04効率的フロンティア分析
  5. 05ポートフォリオのバックテストとリバランス

活用シーン

  1. 01銘柄配分の下方リスク管理
  2. 02分散またはボラティリティ上限の設定
  3. 03リスク回避度別の配分比較
  4. 04保有資産のバックテストや定期リバランス

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/nvidia/skills --skill portfolio-optimization

インストール後、Claude Code で/portfolio-optimizationを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
EVAL.md
evals-full.json
evals.json
references/workflows/
agent_recipes.md

詳細

NVIDIA cuOpt によるポートフォリオ最適化

目的

NVIDIA によって高速化された Mean-CVaR および Mean-Variance 最適化を使用して、定量的なポートフォリオを構築・分析します。portfolio_optimization パッケージを使ってリターンを計算し、CVaR 用の KDE シナリオを生成し、cuOpt GPU ソルバーで分散上限付き Markowitz 配分を SOCP/QCQP 問題として解き、効率的フロンティアを描画し、ポートフォリオをバックテストし、価格データからリバランスのワークフローを実行します。

使用する場面

次のようなタスクでは、このスキルを使用してください。

  • 株価から Mean-CVaR ポートフォリオを構築または最適化する。
  • 下方 CVaR リスクを抑えながら、ティッカー間のウェイトを配分する。
  • cuOpt の SOCP/QCQP サポートを使い、厳格な分散またはボラティリティ上限付きの Mean-Variance または Markowitz 配分を解く。
  • ポートフォリオの対象銘柄群について、効率的フロンティアを描画または確認する。
  • リスク回避度別のウェイト表を作成する。
  • 最適化されたポートフォリオをベンチマークと比較してバックテストする。
  • スケジュールまたは乖離トリガーに基づいてポートフォリオをリバランスする。
  • S&P 500、S&P 100、Dow 30、またはユーザー提供の価格データセットでワークフローを実行する。

よくある起動フレーズには、「ポートフォリオを最適化して」「CVaR ポートフォリオを構築して」「これらのティッカーを cuOpt で最適化して」「cuOpt で解いて」「効率的フロンティアを描画して」「リスク回避度別のウェイトを表示して」「この配分をバックテストして」「毎月リバランスして」「保有銘柄を CVaR で分析して」「配分を比較して」「下方リスクを軽減して」「配分を構築して」「配分の選択肢を評価して」「保有銘柄をストレステストして」「下方リスクへのエクスポージャーを評価して」「ウェイト上限のもとで保有銘柄を見直して」「ベンチマークポートフォリオを比較して」「CVaR シナリオをシミュレーションして」「ポートフォリオリスクをスクリーニングして」「制約下で保有銘柄を最適化して」「分散上限付きポートフォリオを解いて」「SOCP を使って」「ボラティリティ上限を設定して」「より低リスクの配分を見つけて」などがあります。

一般的な金融の概要、価格予測、ニューラルネットワークのトレーニング、車両経路問題、またはポートフォリオ以外の最適化には使用しないでください。

前提条件

  • portfolio_optimization パッケージがインストールされた Python 環境。
  • cuOpt と cuML がインストールされた NVIDIA GPU ランタイム。Mean-Variance SOCP ワークフローには、26.06 系以降など、QCQP/SOCP をサポートする cuOpt ビルドが必要です。
  • ホスト環境とワークフローに適合する CUDA エクストラ:CUDA 12 で cuOpt/cuML 26.06 をフルに使用する場合は uv sync --extra cuda12、現在の CUDA 13 スタックをフルに使用する場合は uv sync --extra cuda13、cuOpt 26.06 による CUDA 13 の SOCP のみの検証には uv sync --extra cuda13-socp。
  • cp.CUOPT を提供する cvxpy。
  • デフォルトの価格 CSV をダウンロードする必要がある場合は、初回実行時にネットワークアクセスが必要です。

セットアップ

このスキルは、インストール済みの portfolio_optimization パッケージを使用します。環境は、Brev の起動可能な環境から、または適合する CUDA エクストラをインストールした NVIDIA-AI-Blueprints/portfolio-optimization リポジトリから用意できます。

パッケージ化されたエージェント/評価用サンドボックスでは、portfolio_optimization は個別に公開された wheel ではなく、PYTHONPATH 経由で利用できる場合があります。見つからないと判断する前に、python -c "import portfolio_optimization" でローカルパッケージを確認してください。pip install portfolio_optimization は実行しないでください。サンプルのワークフローを一から再実装したり、パッケージの API を汎用的な pandas/scipy/cvxpy のポートフォリオコードに置き換えたりしないでください。

具体的な実装の詳細については、信頼できる情報源として references/workflows/agent_recipes.md を参照してください。価格の読み込み、リターンの準備、cuOpt での解法、25 点のフロンティアの構築、等ウェイトとの比較によるバックテスト、リバランサーの呼び出しについて、正確で動作する形式が記載されています。

デフォルトのデータセットは data/stock_data/sp500.csv です。これは gitignore 対象です。初回ダウンロードの前に、パッケージの yfinance データヘルパーを介して公開市場データを取得することをユーザーに伝え、確認を求めてください。

import cvxpy as cp
from portfolio_optimization.cvar_parameters import CvarParameters
from portfolio_optimization.utils import download_data

download_data("data/stock_data", datasets=["sp500"])
CVAR_SOLVER_SETTINGS = {"solver": cp.CUOPT, "verbose": False, "solver_method": "PDLP"}
cvar_params = CvarParameters(
    w_min=0.0, w_max=1.0,
    c_min=0.0, c_max=0.0,
    risk_aversion=1.0, confidence=0.95,
)

手順

実行前に、適用するデフォルト設定を簡潔に説明し、その後、次のガードレールに従ってください。

  1. data/stock_data/sp500.csv を読み込みます。存在しない場合は、portfolio_optimization.utils.download_data で sp500 をダウンロードしてよいか確認してください。価格データを glob したり、代替したり、捏造したりしないでください。
  2. 求解の前にユーザーの CSV を検証します。日付形式のインデックスまたは先頭の日付列、数値のティッカー列、日付フィルタ後に少なくとも 60 行、および要求されたティッカーが少なくとも 1 つ必要です。ユーザーが開始日/終了日を指定した場合は、リターン計算の前に価格 DataFrame をスライスし、保持された日付範囲を報告してください。ティッカーのフィルタは、リターンを計算する前に価格 DataFrame に対して行います。regime_dict はティッカーフィールドを取りません。
  3. utils.calculate_returns(...) で LOG リターンを計算します。
  4. Mean-CVaR タスクでは、cvar_utils.generate_cvar_data(...)、KDE、および KDESettings(device="GPU") でシナリオを生成します。Mean-Variance SOCP の分散上限タスクでは、CVaR シナリオを生成せず、LOG リターン計算後の returns_dict を直接使用してください。
  5. 通常の Mean-CVaR ポートフォリオ要求では、明示的な w_min と w_max を指定して CvarParameters を定義し、c_min=0.0 および c_max=0.0 を設定して、結果が 100 パーセント現金ではなく完全投資になるようにします。
  6. 分散上限、ボラティリティ上限、Markowitz、SOCP、または QCQP の要求では、正の分散上限を var_limit に設定し、c_min=0.0、c_max=0.0、およびロングオンリーで完全投資の配分には L_tar=1.0 を指定して MeanVarianceParameters を定義します。ユーザーがボラティリティ上限を指定した場合は、var_limit に代入する前に二乗してください。
  7. Mean-CVaR タスクでは cvar_optimizer.CVaR(returns_dict, cvar_params) を構築します。直接 cuOpt の Mean-Variance SOCP タスクでは mean_variance_optimizer.MeanVariance(returns_dict, mean_variance_params, api_settings=ApiSettings(api="cuopt_python")) を構築します。
  8. NVIDIA cuOpt のみで求解します。CVaR では、hasattr(cp, "CUOPT") および str(cp.CUOPT) in {str(s) for s in cp.installed_solvers()} を確認し、単発の求解またはループによるフロンティア求解のたびに CVAR_SOLVER_SETTINGS を渡してください。直接 Mean-Variance SOCP では、cuopt Python パッケージがインポート可能であることを確認し、api="cuopt_python" でオプティマイザーを呼び出します。cuOpt は二次制約に対してバリア法を自動選択します。CLARABEL、SCS、ECOS、またはその他の CPU ソルバーにフォールバックしないでください。cuOpt が存在しない場合は、検証/セットアップを完了し、CPU の結果を捏造するのではなく、GPU/cuOpt ランタイムが存在しないことを報告してください。
  9. カスタム制約については、ユーザーの要求を適切なパラメーターモデルにマッピングします。CVaR のリスク制御は CvarParameters に、分散またはボラティリティの上限は MeanVarianceParameters.var_limit に、ウェイト上限は w_min/w_max に、リスク選好度は risk_aversion に、信頼水準は confidence に、現金許容額は c_max にマッピングします。パッケージが明示的な混合整数錐計画のサポートを公開していない限り、カーディナリティと SOCP の組み合わせは未サポートとして扱ってください。
  10. ユーザーがバックテスト用のベンチマークを省略した場合は、同じティッカーによる等ウェイトポートフォリオを使用します。ユーザーが制約を省略した場合は、デフォルト表の値を保持し、求解前に重要となる前提を簡潔に再確認してください。
  11. 配分順にソートしたウェイト、現金ウェイト、期待リターン、ソルバーラベル(cuOpt GPU)、および使用したリスク指標を提示します。リスク指標は、Mean-CVaR では CVaR、SOCP では実現分散と var_limit です。要求されたフロンティア図、ウェイト表、バックテスト指標、またはリバランススケジュールを含めてください。表では、ティッカーを列または行として小数のウェイトとパーセンテージを含めます。プロットでは、パッケージが返した図をそのまま保持し、ゼロから描き直さないでください。
  12. レポート品質の回答では、要求されたワークフローが実際に実行された証拠を含めます。効率的フロンティアでは、len(results_df) を明記し、要求された ra_num を使用します(ユーザーが別途指定しない限り 25)。分散上限 SOCP 求解では、result_row["solver"]、実現分散、要求された var_limit を報告し、実現分散が上限以下であることを確認します。ウェイト表では、results_df["weights"] をティッカー列に展開し、cash と risk_aversion を含めます。バックテストでは、最適化ポートフォリオとベンチマークポートフォリオの両方について mean portfolio return、sharpe、sortino、max drawdown を含めます。リバランスでは、results_dataframe、re_optimize_dates、および cumulative_portfolio_value の末尾を含めます。

標準ワークフローのひな形

該当するポートフォリオ最適化タスクは、この形式から始め、要求された出力に合わせて必要な箇所だけを調整します。コピーしてすぐに使える関数については、独自のコードを書く前に references/workflows/agent_recipes.md を参照してください。

平均-CVaR ワークフロー
import cvxpy as cp
import pandas as pd

from portfolio_optimization import backtest, cvar_optimizer, cvar_utils, rebalance, utils
from portfolio_optimization.cvar_parameters import CvarParameters
from portfolio_optimization.portfolio import Portfolio
from portfolio_optimization.settings import KDESettings, ReturnsComputeSettings, ScenarioGenerationSettings

if not hasattr(cp, "CUOPT") or str(cp.CUOPT) not in {str(s) for s in cp.installed_solvers()}:
    raise RuntimeError("cuOpt GPU solver is required; do not substitute a CPU solver.")

CVAR_SOLVER_SETTINGS = {"solver": cp.CUOPT, "verbose": False, "solver_method": "PDLP"}

prices = utils.get_input_data("data/stock_data/sp500.csv")
returns_dict = utils.calculate_returns(
    prices,
    regime_dict=None,
    returns_compute_settings=ReturnsComputeSettings(return_type="LOG"),
)
returns_dict = cvar_utils.generate_cvar_data(
    returns_dict,
    ScenarioGenerationSettings(
        fit_type="kde",
        kde_settings=KDESettings(device="GPU"),
    ),
)
cvar_params = CvarParameters(
    w_min=0.0,
    w_max=1.0,
    c_min=0.0,
    c_max=0.0,
    risk_aversion=1.0,
    confidence=0.95,
)
optimizer = cvar_optimizer.CVaR(returns_dict, cvar_params)
result, optimal_portfolio = optimizer.solve_optimization_problem(
    solver_settings=CVAR_SOLVER_SETTINGS,
    print_results=False,
)
平均-分散 SOCP ワークフロー
import importlib.util
import numpy as np

from portfolio_optimization import mean_variance_optimizer, utils
from portfolio_optimization.mean_variance_parameters import MeanVarianceParameters
from portfolio_optimization.settings import ApiSettings, ReturnsComputeSettings

if importlib.util.find_spec("cuopt") is None:
    raise RuntimeError("cuOpt Python API is required; do not substitute a CPU solver.")

prices = utils.get_input_data("data/stock_data/sp500.csv")
returns_dict = utils.calculate_returns(
    prices,
    regime_dict=None,
    returns_compute_settings=ReturnsComputeSettings(return_type="LOG"),
)
weights = np.ones(len(returns_dict["tickers"])) / len(returns_dict["tickers"])
var_limit = float(weights @ returns_dict["covariance"] @ weights) * 1.05
mean_variance_params = MeanVarianceParameters(
    w_min=0.0,
    w_max=1.0,
    c_min=0.0,
    c_max=0.0,
    L_tar=1.0,
    var_limit=var_limit,
)
optimizer = mean_variance_optimizer.MeanVariance(
    returns_dict,
    mean_variance_params,
    api_settings=ApiSettings(api="cuopt_python"),
)
result, optimal_portfolio = optimizer.solve_optimization_problem(print_results=False)
realized_variance = float(
    optimal_portfolio.weights @ returns_dict["covariance"] @ optimal_portfolio.weights
)

効率的フロンティアまたはウェイトの表を作成するには、次を呼び出します。

results_df, fig, ax = cvar_utils.create_efficient_frontier(
    returns_dict,
    cvar_params,
    CVAR_SOLVER_SETTINGS,
    ra_num=25,
    show_plot=False,
    show_discretized_portfolios=False,
    benchmark_portfolios=False,
    print_portfolio_results=False,
)
weights_table = pd.DataFrame(results_df["weights"].tolist(), index=results_df.index)

ベンチマークのバックテストでは、最適化された配分を Portfolio(name="cuOpt Optimal", tickers=returns_dict["tickers"], weights=optimal_portfolio.weights, cash=optimal_portfolio.cash) でラップし、同じ returns_dict["tickers"] を使って均等加重の Portfolio を作成します。その後、backtest.portfolio_backtester(..., test_method="historical").backtest_against_benchmarks(...) を使います。バックテスターは (backtest_results, ax) を返します。

月次リバランスでは、まず価格の DataFrame を CSV パスに書き込みます。re_optimize_criteria={"type": "drift_from_optimal", "threshold": 0, "norm": 1} を指定して rebalance.rebalance_portfolio(dataset_directory=<csv_path>, ...) をインスタンス化し、re_optimize(transaction_cost_factor=..., plot_title="Monthly Rebalancing") を呼び出します。リバランサーは (results_dataframe, re_optimize_dates, cumulative_portfolio_value) を返します。

データとデフォルト設定

設定デフォルト
データセットdata/stock_data/sp500.csv
期間利用可能な全期間
ポートフォリオの種類ロングオンリー
最大ウェイト指定がない場合はなし
リスク回避度1.0
信頼度0.95
シナリオ手法GPU 上の KDE
ソルバーCVaR:PDLP を使用する cuOpt GPU、平均-分散 SOCP:バリア法が自動選択される cuOpt Python API の直接呼び出し
リバランス要求がない場合はなし

デフォルトの S&P 500 ファイルは過去時点のスナップショットであり、現在の構成銘柄が含まれていない場合があります。ユーザー提供の CSV は、utils.get_input_data と互換性のある、ティッカーを列とする日付インデックス付きの価格テーブルにしてください。要求されたティッカーが存在しない場合は、それらを除外して、除外したものを報告し、ユーザーが他のデータの取得を明示的に求めていない限り、利用可能な列を使って続行します。

主要な API

ポートフォリオの計算やシミュレーションループを再実装せず、パッケージの API を使用してください。portfolio_optimization ヘルパーはフラットなオブジェクトを返します。returns_dict には returns、mean、covariance、tickers などのキーが含まれます。returns_dict["regime_1"] のようにインデックスを指定しないでください。solve_optimization_problem(...) が返すのは (result_row, portfolio) であり、入れ子になった結果の辞書ではありません。

  • リターン:utils.calculate_returns(input_dataset, regime_dict, returns_compute_settings)。
  • レジームフィルター:regime_dict は None、または {"name": "...", "range": ("YYYY-MM-DD", "YYYY-MM-DD")} です。レジーム名をキーとする辞書ではなく、ティッカーも含みません。
  • シナリオ:Mean-CVaR の場合に限り、cvar_utils.generate_cvar_data(returns_dict, scenario_generation_settings) を使用します。
  • CVaR オプティマイザー:cvar_optimizer.CVaR(returns_dict, cvar_params)。
  • Mean-Variance SOCP オプティマイザー:mean_variance_optimizer.MeanVariance(returns_dict, mean_variance_params, api_settings=ApiSettings(api="cuopt_python"))。
  • CVaR の求解:result_row, portfolio = cvar_problem.solve_optimization_problem(solver_settings=CVAR_SOLVER_SETTINGS, print_results=False)。
  • SOCP の求解:result_row, portfolio = mean_variance_problem.solve_optimization_problem(print_results=False)。
  • 効率的フロンティア:cvar_utils.create_efficient_frontier(returns_dict, cvar_params, solver_settings=CVAR_SOLVER_SETTINGS, ra_num=25)。返される results_df には、指標、weights の辞書列、cash が含まれます。
  • ポートフォリオ:Portfolio(name="", tickers=None, weights=None, cash=0.0, time_range=None)。ティッカーと、それらに対応するフラットな配列形式の weights を渡します。
  • バックテスト:最適化後の配分と各ベンチマークについて、portfolio.Portfolio オブジェクトを作成します。均等加重ベンチマークには、重み 1 / len(tickers) と cash=0.0 を使用します。その後、backtest.portfolio_backtester(test_portfolio, returns_dict, risk_free_rate=0.0, test_method="historical", benchmark_portfolios=[...]).backtest_against_benchmarks(...) を呼び出します。
  • リバランス:rebalance.rebalance_portfolio(...) の dataset_directory には、DataFrame ではなく CSV のパスが必要です。re_optimize(...) を呼び出します。これは (results_dataframe, re_optimize_dates, cumulative_portfolio_value) を返します。
  • 設定モデル:ReturnsComputeSettings、ScenarioGenerationSettings、KDESettings、ApiSettings、CvarParameters、MeanVarianceParameters。

使用例

  • 「S&P 500 から最適なポートフォリオを構築する」:価格データを読み込み、LOG リターンを計算し、GPU KDE シナリオを生成して、ロングオンリーかつ完全投資の CvarParameters を設定し、cuOpt で解き、分散された重みとリターン/CVaR を報告します。
  • 「SOCP で分散上限のあるポートフォリオを解く」:価格データを読み込み、LOG リターンを計算し、MeanVarianceParameters(var_limit=...) を設定して、api="cuopt_python" を直接指定して解き、期待リターン、実現分散、var_limit、重みを報告します。
  • 「効率的フロンティアをプロットする」:create_efficient_frontier(...) を呼び出して results_df を返し、リクエストに応じて図を表示または保存します。
  • 「リスク回避度別の重みを表示する」:results_df["weights"] を展開して、資産ごとのテーブルを作成します。
  • 「均等加重と比較してバックテストする」:最適化後の Portfolio オブジェクトと均等加重の Portfolio オブジェクトを作成し、パッケージのバックテスト機能を使用してシャープレシオ、ソルティノレシオ、最大ドローダウンを報告します。
  • 「月次リバランスをバックテストする」:前述のドリフトトリガーを指定して rebalance_portfolio を設定し、re_optimize(transaction_cost_factor=...) を実行します。

制限事項

  • cuOpt と cuML を備えた NVIDIA GPU が必要です。CPU ソルバーは意図的に許可されていません。
  • Mean-Variance SOCP の分散上限には、cuOpt の QCQP/SOCP サポートが必要です。CUDA エクストラをインストールする場合は、26.06 系以降を使用してください。
  • cuda13-socp は、cuml-cu13 26.06 がまだ公開されていないため、cuML を含めずに cuOpt をインストールします。直接的な SOCP/QCQP の検証には使用できますが、GPU KDE CVaR ワークフローには使用しないでください。
  • Cardinality と SOCP の組み合わせは、パッケージが明示的な混合整数錐サポートを提供していない限り、未サポートとして扱われます。
  • CPU のみの評価用コンテナでも、ルーティング、データ処理、レポート動作は検証できますが、有効な cuOpt ソルブは実行できません。その場合は、GPU/cuOpt ランタイムが不足していることを明示してください。
  • デフォルトの価格データは過去のスナップショットであり、現在の構成銘柄が含まれていない場合があります。
  • 初回のデータセットダウンロードには、ユーザーが CSV を提供しない限り、ネットワークアクセスが必要です。

トラブルシューティング

  • デフォルト CSV が見つからない、または FileNotFoundError が発生する場合:パッケージが download_data("data/stock_data", datasets=["sp500"]) で公開市場データを取得することを説明してください。実行するのは、ユーザーの確認後に限ってください。
  • SolverError または cp.CUOPT が見つからない場合:ホストに適合する CUDA エクストラをインストールし、python -c "import cvxpy as cp; print(hasattr(cp, 'CUOPT'), cp.installed_solvers())" で確認してください。
  • cuml の ImportError または GPU KDE の失敗が発生する場合:python -c "import cuml" で cuML が存在することを確認し、KDESettings(device="GPU") を維持してください。cuda13-socp を使用している場合、CVaR/KDE ではこれは想定どおりです。cuML を使用するワークフローには cuda12 または cuda13 に切り替えてください。
  • SOCP の設定がソルブ前に失敗する場合:インストール済みの cuopt パッケージが 26.06 系以降であること、および MeanVarianceParameters.var_limit が正であることを確認してください。
  • 通常の最適化で現金のみが返される場合:CvarParameters で c_max=0.0 を設定してください。
  • ソルバーが実行不可能または解なしと報告する場合:矛盾する境界条件、要求された上限/cardinality に対してティッカー数が少なすぎること、またはデータが少なすぎる日付フィルターがないか確認してください。要求を実行可能にするために必要な、最小限の制約変更を報告してください。
  • 要求されたティッカーがデフォルト CSV に存在しない場合:該当するティッカーを報告し、残りの要求されたティッカーで続行してください。
  • ユーザーの CSV が検証に失敗する場合:日付をインデックスとする価格テーブル、または第 1 列が日付で残りの列が数値のティッカー価格である CSV を求めてください。フィルター後に最低 60 行が必要であることも伝えてください。

コメント