cufolio について
cuFOLIO は、NVIDIA GPU を活用した定量ポートフォリオ構築・分析スキルです。cuFOLIO パッケージと cuOpt ソルバーを使い、Mean-CVaR 最適化、効率的フロンティア、バックテスト、リバランスを扱います。
主な機能
- 01Mean-CVaR ポートフォリオ最適化
- 02GPU による KDE シナリオ生成
- 03効率的フロンティア分析
- 04ポートフォリオのバックテスト
- 05定期または乖離条件によるリバランス
活用シーン
- 01下方リスクを考慮した銘柄配分の最適化
- 02リスク回避度別の配分比較
- 03ベンチマークとのポートフォリオ比較
- 04ポートフォリオのリバランス検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nvidia/ skills --skill cufolioインストール後、Claude Code で/cufolioを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
BENCHMARK.mdskill-card.mdskill.oms.sigevals/EVAL.mdevals-full.jsonevals.jsonreferences/workflows/agent_recipes.md詳細
cuFOLIO スキル
目的
NVIDIA によって高速化された Mean-CVaR 最適化を使用して、定量ポートフォリオを構築・分析します。cuFOLIO を使用してリターンを計算し、KDE シナリオを生成し、cuOpt GPU ソルバーで配分を解き、効率的フロンティアを追跡し、ポートフォリオをバックテストし、価格データからリバランスのワークフローを実行します。
使用するタイミング
次のタスクを行う場合に、このスキルを使用します。
- 株価から Mean-CVaR ポートフォリオを構築または最適化する。
- 下方 CVaR リスクを抑えながら、ティッカー間のウェイトを配分する。
- ポートフォリオの投資対象全体について、効率的フロンティアをプロットまたは確認する。
- リスク許容度別のウェイト表を作成する。
- 最適化したポートフォリオをベンチマークと比較してバックテストする。
- スケジュールまたはドリフトのトリガーに基づいてポートフォリオをリバランスする。
- S&P 500、S&P 100、Dow 30、またはユーザーが指定した価格データセットでワークフローを実行する。
一般的なトリガーフレーズには、「ポートフォリオを最適化して」「CVaR ポートフォリオを構築して」「これらのティッカーに cuFOLIO を使って」「cuOpt で解いて」「効率的フロンティアをプロットして」「リスク許容度別のウェイトを表示して」「この配分をバックテストして」「毎月リバランスして」「保有資産を CVaR で分析して」「配分を比較して」「下方リスクを低減して」「配分を構成して」「配分の選択肢を評価して」「保有資産のストレステストをして」「下方リスクへのエクスポージャーを評価して」「ウェイト上限のもとで保有資産を見直して」「ベンチマークポートフォリオを比較して」「CVaR シナリオをシミュレーションして」「ポートフォリオのリスクをスクリーニングして」「制約条件下で保有資産を最適化して」「より低リスクの配分を探して」などがあります。
一般的な金融の要約、価格予測、ニューラルネットワークのトレーニング、車両経路問題、ポートフォリオ以外の最適化には使用しないでください。
前提条件
cufolioパッケージがインストールされた Python 環境。- cuOpt と cuML がインストールされた NVIDIA GPU ランタイム。
- ホストに適合する CUDA エクストラ(例:
uv sync --extra cuda12またはuv sync --extra cuda13)。 cp.CUOPTを公開するcvxpy。- デフォルトの価格 CSV をダウンロードする必要がある場合は、初回実行時にネットワークアクセスが必要です。
セットアップ
このスキルは、インストール済みの cufolio パッケージを使用します。利用可能な環境は、Brev のランチャブル環境、または対応する CUDA エクストラをインストールした NVIDIA-AI-Blueprints/cuFOLIO から用意できます。
パッケージ化されたエージェント/評価用サンドボックスでは、cufolio が個別に公開された wheel ではなく、PYTHONPATH 経由で利用できる場合があります。不足していると判断する前に、python -c "import cufolio" でローカルパッケージを確認してください。pip install cufolio は実行せず、cuFOLIO のワークフローを一から再実装せず、パッケージ API を汎用的な pandas/scipy/cvxpy のポートフォリオコードに置き換えないでください。
具体的な実装の詳細については、信頼できる情報源である references/workflows/agent_recipes.md を参照してください。価格の読み込み、リターンの準備、cuOpt での最適化、25 点のフロンティアの構築、等ウェイトとのバックテスト、リバランサーの呼び出しについて、実際に動作する正確な形式が記載されています。
デフォルトのデータセットは data/stock_data/sp500.csv です。これは Git の追跡対象外です。初回ダウンロードの前に、cuFOLIO/yfinance のデータヘルパーを通じて公開市場データを取得することをユーザーに伝え、次の操作について確認を得てください。
import cvxpy as cp
from cufolio.cvar_parameters import CvarParameters
from cufolio.utils import download_data
download_data("data/stock_data", datasets=["sp500"])
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,
)
手順
実行前に適用するデフォルトを簡潔に述べてから、次のガードレールに従ってください。
data/stock_data/sp500.csvを読み込みます。存在しない場合は、cufolio.utils.download_dataでsp500をダウンロードする前に確認してください。価格データを glob で検索したり、代替したり、捏造したりしないでください。- 解決に取りかかる前に、ユーザーの CSV を検証します。日付形式のインデックスまたは最初の日付列、数値形式のティッカー列、日付でフィルタリングした後に少なくとも 60 行、そしてリクエストされたティッカーが少なくとも 1 つ含まれていることを必須とします。ユーザーが開始日/終了日を指定した場合は、リターンを計算する前に価格 DataFrame をスライスし、保持された日付範囲を報告します。リターンの計算前に、価格 DataFrame でティッカーをフィルタリングしてください。
regime_dictはティッカーフィールドを受け取りません。 utils.calculate_returns(...)を使って LOG リターンを計算します。- KDE と
KDESettings(device="GPU")を使い、cvar_utils.generate_cvar_data(...)でシナリオを生成します。 CvarParametersは、明示的なw_minとw_maxを指定して定義します。通常の「最適ポートフォリオを構築する」リクエストでは、現金 100% ではなく全額投資となるよう、c_min=0.0とc_max=0.0を設定します。- リターン辞書から直接
cvar_optimizer.CVaR(returns_dict, cvar_params)を構築します。ティッカー、シナリオ配列、平均値、共分散は、cuFOLIO ヘルパーが返す形状のまま維持してください。 - NVIDIA cuOpt のみを使って解きます。解く前に、
hasattr(cp, "CUOPT")とstr(cp.CUOPT) in {str(s) for s in cp.installed_solvers()}を確認してください。単発の solve またはループによるフロンティア solve のすべてにSOLVER_SETTINGSを渡してください。CLARABEL、SCS、ECOS、その他の CPU ソルバーには決してフォールバックしないでください。cuOpt が利用できない場合は、検証とセットアップを完了したうえで、GPU/cuOpt ランタイムが不足していると報告し、CPU による結果を捏造しないでください。 - カスタム制約は、ユーザーのリクエストを
CvarParametersに対応付けます。ウェイト上限はw_min/w_max、リスク許容度はrisk_aversion、信頼水準はconfidence、現金の許容額はc_maxに対応付けます。カーディナリティ制約は、そのワークフローでパッケージが明示的な資産数制約を公開している場合に限り適用します。制約が両立しない場合(たとえば、指定されたティッカー数に対して最大ウェイトが低すぎる場合)は、どの制約を緩和するかを推測せず、矛盾を説明して確認してください。 - ユーザーがバックテストのベンチマークを指定しない場合は、同じティッカーを使った均等ウェイトのポートフォリオを使用します。制約が指定されていない場合は、デフォルト表の値を維持し、解く前に重要な前提を簡潔に言い直してください。
- 配分順に並べたウェイト、現金ウェイト、期待リターン、CVaR、ソルバーラベル(
cuOpt GPU)、およびリクエストされたフロンティア図、ウェイト表、バックテスト指標、またはリバランススケジュールを提示します。表では、ティッカーを列または行として含め、10進数のウェイトとパーセンテージを記載します。プロットでは、最初から描き直さず、返された cuFOLIO の図を保持してください。 - レポート品質が求められる回答では、リクエストされたワークフローを実際に実行した証拠を含めます。効率的フロンティアでは
len(results_df)を示し、指定されたra_num(ユーザーの指定がない場合は 25)を使用します。ウェイト表ではresults_df["weights"]をティッカー列に展開し、cashとrisk_aversionを含めます。バックテストでは、最適化ポートフォリオとベンチマークポートフォリオの両方について、mean portfolio return、sharpe、sortino、max drawdownを含めます。リバランスでは、results_dataframe、re_optimize_dates、およびcumulative_portfolio_valueの末尾を含めます。
標準的なワークフローのひな形
肯定的な cuFOLIO タスクはこの形式から始め、要求された出力だけに合わせて調整してください。コピーして使える完全な関数については、カスタムコードを書く前に references/workflows/agent_recipes.md を読んでください。
import cvxpy as cp
import pandas as pd
from cufolio import backtest, cvar_optimizer, cvar_utils, rebalance, utils
from cufolio.cvar_parameters import CvarParameters
from cufolio.portfolio import Portfolio
from cufolio.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.")
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=SOLVER_SETTINGS,
print_results=False,
)
効率的フロンティアまたはウェイトの表を作成するには、次を呼び出します。
results_df, fig, ax = cvar_utils.create_efficient_frontier(
returns_dict,
cvar_params,
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 |
| ソルバー | PDLP を使用する cuOpt GPU |
| リバランス | 要求がない場合はなし |
デフォルトの S&P 500 ファイルは過去の時点のスナップショットであり、現在の構成銘柄が含まれていない場合があります。ユーザー提供の CSV は、utils.get_input_data と互換性のある、ティッカー列を含む日付インデックス付きの価格テーブルにしてください。要求されたティッカーが存在しない場合は、それらを除外し、除外した銘柄を報告したうえで、ユーザーが別のデータの取得を明示的に要求していない限り、利用可能な列を使って処理を続けてください。
主な API
ポートフォリオの計算やシミュレーションループを再実装せず、パッケージの API を使用してください。cuFOLIO のヘルパーが返すのはフラットなオブジェクトです。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")}です。レジーム名をキーにした辞書ではなく、ティッカーも含みません。 - シナリオ:
cvar_utils.generate_cvar_data(returns_dict, scenario_generation_settings)。 - オプティマイザー:
cvar_optimizer.CVaR(returns_dict, cvar_params)。 - 解決:
result_row, portfolio = cvar_problem.solve_optimization_problem(solver_settings=SOLVER_SETTINGS, print_results=False)。 - 効率的フロンティア:
cvar_utils.create_efficient_frontier(returns_dict, cvar_params, solver_settings=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。
例
- 「S&P 500 から最適なポートフォリオを構築する」:価格を読み込み、LOG リターンを計算し、GPU KDE シナリオを生成して、ロングオンリーで全額投資する
CvarParametersを設定し、cuOpt で解き、分散されたウェイトとリターン/CVaR を報告します。 - 「効率的フロンティアをプロットする」:
create_efficient_frontier(...)を呼び出し、results_dfを返して、要求に応じて図を表示または保存します。 - 「リスク回避度ごとのウェイトを教えて」:
results_df["weights"]を銘柄ごとのテーブルに展開します。 - 「均等加重と比較してバックテストする」:最適化ポートフォリオと均等加重ポートフォリオの
Portfolioオブジェクトを作成し、cuFOLIO のバックテスターを使用して、シャープレシオ、ソルティノレシオ、最大ドローダウンを報告します。 - 「月次リバランスでバックテストする」:上記のドリフトトリガーを使って
rebalance_portfolioを設定し、re_optimize(transaction_cost_factor=...)を実行します。
制限事項
- cuOpt と cuML を備えた NVIDIA GPU が必要です。CPU ソルバーは意図的に使用できないようになっています。
- CPU のみの評価コンテナーでも、ルーティング、データ処理、レポート動作は検証できますが、有効な cuOpt ソルバー実行はできません。その場合は、GPU/cuOpt ランタイムがないことを明示してください。
- デフォルトの価格データは過去のスナップショットであり、現在の構成銘柄が含まれていない場合があります。
- 初回のデータセットダウンロードには、ユーザーから CSV が提供されない限り、ネットワーク接続が必要です。
トラブルシューティング
- デフォルトの CSV がない、または
FileNotFoundErrorが発生する場合:cuFOLIO は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")を維持してください。- 通常の最適化で現金のみが返される場合:
CvarParametersでc_max=0.0を設定してください。 - ソルバーが実行不可能または解なしと報告する場合:矛盾する境界条件、要求された上限/銘柄数制約に対するティッカー数の不足、またはデータが少なすぎる日付フィルターがないかを確認し、要求を実行可能にするために変更が必要な制約を最小限で報告してください。
- 要求されたティッカーがデフォルトの CSV にない場合:該当するティッカーを報告し、残りの要求されたティッカーで続行してください。
- ユーザーの CSV が検証に失敗する場合:日付をインデックスとする価格テーブル、または最初の列が日付で残りの列が数値のティッカー価格である CSV を求めてください。フィルター適用後に最低 60 行が必要であることも伝えてください。