mcpField
C
cufolio

cufolio

github.com/nvidia数据与数据库3.8k1.7k 次安装今天更新
代码仓库

关于 cufolio

cuFOLIO 是面向量化投资组合构建与分析的技能,使用 NVIDIA GPU 加速。它通过 cuFOLIO 包和 cuOpt 求解器支持 Mean-CVaR 优化、有效前沿分析、回测及再平衡。

主要功能

  1. 01Mean-CVaR 投资组合优化
  2. 02GPU KDE 情景生成
  3. 03有效前沿分析
  4. 04投资组合回测
  5. 05按计划或漂移触发再平衡

适用场景

  1. 01按下行风险优化股票代码配置
  2. 02比较不同风险厌恶度下的权重
  3. 03将配置与基准进行回测
  4. 04模拟投资组合再平衡

安装

复制下面的命令,在终端中运行。

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

安装后在 Claude Code 中输入/cufolio确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
EVAL.md
evals-full.json
evals.json
references/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。
  • cvxpy 提供 cp.CUOPT。
  • 如果必须下载默认价格 CSV,首次运行时需要网络访问。

设置

此技能调用已安装的 cufolio 包。可通过 Brev launchable 或在 NVIDIA-AI-Blueprints/cuFOLIO 中安装匹配的 CUDA 附加项来准备环境。

在打包的 Agent/评估沙箱中,cufolio 可能通过 PYTHONPATH 提供,而不是作为单独发布的 wheel 提供。声明缺少该包之前,先运行 python -c "import cufolio" 验证本地包。不要运行 pip install cufolio,不要从头重新实现 cuFOLIO 工作流,也不要用通用 pandas/scipy/cvxpy 投资组合代码替代包 API。

具体实现细节请以 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,
)

说明

执行前简要说明将采用的默认设置,然后遵循以下防护规则:

  1. 加载 data/stock_data/sp500.csv;如果文件缺失,先征求用户同意,再使用 cufolio.utils.download_data 下载 sp500。不得使用 glob 查找、替换或伪造价格数据。
  2. 求解前验证用户提供的 CSV:要求有类似日期的索引或第一列日期列、数值型 ticker 列、日期筛选后至少保留 60 行,并且至少包含一个用户请求的 ticker。如果用户提供了起止日期,先对价格 DataFrame 切片,再计算收益率,并报告保留的日期范围。计算收益率前,先在价格 DataFrame 中筛选 ticker。regime_dict 不接受 ticker 字段。
  3. 使用 utils.calculate_returns(...) 计算对数收益率。
  4. 使用 cvar_utils.generate_cvar_data(...)、KDE 和 KDESettings(device="GPU") 生成情景。
  5. 显式设置 w_min 和 w_max 来定义 CvarParameters。对于一般的“构建最优投资组合”请求,将 c_min=0.0 和 c_max=0.0,确保资金全部投入,而不是 100% 持有现金。
  6. 直接从该收益率字典构建 cvar_optimizer.CVaR(returns_dict, cvar_params);保持 ticker、情景数组、均值和协方差的形状与 cuFOLIO 辅助函数返回的形状一致。
  7. 仅使用 NVIDIA cuOpt 求解。求解前,验证 hasattr(cp, "CUOPT") 和 str(cp.CUOPT) in {str(s) for s in cp.installed_solvers()}。对每次单次求解或循环式有效前沿求解,都传入 SOLVER_SETTINGS。绝不退回使用 CLARABEL、SCS、ECOS 或其他 CPU 求解器。如果没有 cuOpt,则完成验证和设置,并报告缺少 GPU/cuOpt 运行时,而不是伪造 CPU 求解结果。
  8. 对于自定义约束,将用户请求映射到 CvarParameters:权重上限映射到 w_min/w_max,风险偏好映射到 risk_aversion,置信水平映射到 confidence,现金额度映射到 c_max;只有当软件包为该工作流提供显式资产数量约束时,才支持基数约束。如果约束之间存在冲突(例如,最大权重过低,无法覆盖请求的 ticker 数量),应解释冲突并询问用户要放宽哪项约束,不得自行猜测。
  9. 如果用户未指定回测基准,则使用相同 ticker 构建等权投资组合。如果用户未指定约束,则保留默认设置表中的值,并在求解前简要重申会产生显著影响的假设。
  10. 按配置权重排序提供权重、现金权重、预期收益率、CVaR、求解器标签(cuOpt GPU),以及用户要求的有效前沿图、权重表、回测指标或再平衡计划。对于表格,将 ticker 作为列或行,并同时列出小数权重和百分比;对于图表,保留 cuFOLIO 返回的图表,不要从头重新绘制。
  11. 对需要用于报告的回答,提供证据证明实际运行了所请求的工作流。对于有效前沿,注明 len(results_df),并使用用户指定的 ra_num(默认值为 25,除非用户另有指定)。对于权重表,将 results_df["weights"] 展开为 ticker 列,并包含 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
日期范围完整可用范围
投资组合类型仅做多
最大权重除非另有指定,否则为 None
风险厌恶度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 为 CSV 路径,而不是 DataFrame。调用 re_optimize(...);它返回 (results_dataframe, re_optimize_dates, cumulative_portfolio_value)。
  • 设置模型:ReturnsComputeSettings、ScenarioGenerationSettings、KDESettings、ApiSettings 和 CvarParameters。

示例

  • “根据 S&P 500 构建最优投资组合”:加载价格数据,计算对数收益率,生成 GPU KDE 情景,设置仅做多且满仓的 CvarParameters,使用 cuOpt 求解,并报告分散化的权重以及收益率/CVaR。
  • “绘制有效前沿”:调用 create_efficient_frontier(...),返回 results_df,并按要求显示或保存图表。
  • “按风险厌恶程度给出权重”:将 results_df["weights"] 展开为逐资产表格。
  • “与等权投资组合进行回测”:构建优化后的 Portfolio 对象和等权 Portfolio 对象,然后使用 cuFOLIO 回测器,并报告 Sharpe、Sortino 和最大回撤。
  • “回测每月再平衡”:使用上述漂移触发条件配置 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())" 进行验证。
  • 出现 ImportError,无法导入 cuml,或 GPU KDE 失败:确认已安装 cuML(运行 python -c "import cuml"),并保留 KDESettings(device="GPU")。
  • 普通优化返回全现金:在 CvarParameters 中设置 c_max=0.0。
  • 求解器报告不可行或无解:检查边界条件是否矛盾、股票代码数量是否不足以满足指定的上限/基数,或日期筛选后数据是否过少;报告使请求可行所需的最小约束调整。
  • 默认 CSV 中缺少请求的股票代码:报告缺少的代码,并继续处理其余请求的代码。
  • 用户 CSV 未通过验证:请用户提供带日期索引的价格表,或首列为日期、其余列为数值型股票价格的 CSV;说明筛选后至少需要 60 行。

评论

支持 Markdown