金融投资组合优化是一项艰巨但至关重要的任务,长期以来始终面临计算速度与模型复杂性之间的权衡难题。自70年前Markowitz投资组合理论提出以来,尽管均值-方差框架已广泛应用,但涉及大规模模拟、多阶段优化或更精细风险度量的鲁棒性分析,由于计算耗时过长,难以满足动态决策对快速迭代的需求。
本文介绍的量化投资组合优化开发者示例,旨在消除这一权衡。通过利用高性能硬件和并行算法,该方案将原本缓慢的批处理流程转变为高效、可迭代的快速工作流程。
该工作流支持可扩展的策略回测与交互式分析。 NVIDIA cuOpt 开源求解器能够高效求解基于场景的均值-CVaR 投资组合优化问题,其性能持续优于基于 CPU 的先进开源求解器,在大规模问题中求解速度提升最高可达 160 倍。
量化投资组合优化还充分利用了广泛的 CUDA 生态系统。借助 CUDA-X 数据科学 库,可显著加速优化前的数据预处理与场景生成,在从回报分布中进行学习和采样时,速度提升可达 100 倍。
投资组合优化的数学基础
优化的投资组合应能在提高预期回报的同时有效降低风险。Markowitz 提出的经典风险与回报权衡关系可表述为:
传统上,投资组合回报的差异被用作衡量风险的指标。本文选用条件风险值(CVaR)作为替代的风险度量方法,因其能更可靠地评估潜在的尾部损失。此外,CVaR支持数据驱动的投资组合优化,无需对收益的底层分布做出假设。该指标用于衡量收益分布中极端情况下的平均损失。
形式上,对于损失随机变量
::
其中 分别为损失分布的
分位数。
图1展示了每日收益率的概率分布。其中,95%的VaR以红色虚线标示为-4.35%,表示在95%的置信水平下,投资组合的损失预计不会超过4.35%。95%的CVaR以蓝色虚线标示为-5.58%,代表尾部5%最不利情景(即图中阴影区域)的平均损失水平。
对于包含具有不对称收益分布资产的投资组合,CVaR 是一种更为合适的风险度量指标,并已在 Basel III 的市场风险监管规则中取代了 VaR。从数学角度看,CVaR 是一种 一致 风险度量,具备次可加性、平移不变性、正齐次性和单调性,这些特性与 风险分散原则 相一致。
此外,作为一种基于场景的优化方法,其具备可计算处理的转换形式:在置信度水平 下,投资组合
的 CVaR 可表示为抽象形式:
其中, 表示返回场景的概率空间,
则表示特定场景
的概率。
直观来看,该表达式表明投资组合的平均损失低于所有收益情景中某一特定分位数的损失水平。无论资产收益的分布是否服从高斯分布,这种基于情景的描述方式都能使CVaR具有更强的稳健性。当采用线性损失函数 ,并以大小为(情景数量,资产数量)的收益情景矩阵作为输入时,可通过引入辅助变量来替代非负运算符
,从而将CVaR的最小化问题转化为一个线性规划问题。
将其融入风险-收益权衡的表述中,可形成如下数学优化问题,即最大化CVaR调整后的收益:
此外,为模拟真实世界的交易限制,还引入了多项约束条件,包括投资预算集中度限制()、单一资产持仓限制 (
)、无风险资产投资额度限制(
)、杠杆水平限制(
),以及基于现有投资组合或基准的成交量约束(
)。
将产品组合优化从 CPU 转移到 GPU
该均值-CVaR问题具有线性目标函数和线性约束条件,其计算复杂度随收益场景数量和可交易资产数量呈线性增长。在实际投资环境中,可交易资产通常多达数千种,而复杂的场景生成引擎能够轻松生成数十万种不同的收益情景。
随着问题规模的扩大,高性能求解器在高效优化中的作用愈发关键。通过采用 cuOpt 线性规划(LP)求解器,可利用 GPU 加速实现原对偶混合梯度算法(PDLP),有效应对大规模优化问题。当问题规模较大(通常包含超过 1 万个变量和 1 万个约束条件)时,cuOpt 的优势得以充分发挥,显著缩短求解时间。
加速工作流程示例
本节展示了一个基于标准普尔 500 指数中 397 只股票子集的量化投资组合优化开发示例。目标是构建一个多头-空头投资组合,在满足自定义交易约束的前提下,尽可能提升风险调整后的收益。如图 2 所示,整个工作流程分为四个步骤:
- 数据准备:基于历史价格估算收益,并生成CVaR情景
- 优化建模:利用预处理数据构建均值-CVaR投资组合优化模型
- 求解过程:调用cuOpt求解器计算最优投资组合权重
- 回测分析:可视化优化结果,评估组合表现并计算关键绩效指标
第 1 步:数据准备
假设在优化周期内收益分布保持稳定,并利用历史收益来估计未来收益。若该假设不成立,可转而优化预期收益分布,以纳入市场条件可能发生变化的因素。
以第一种方法为例,加载从2022年1月1日至2024年7月1日期间的成交价格,计算每日对数收益率。随后,对这些收益率拟合核密度估计模型(KDE),并基于该模型模拟生成两万个收益率情景。
...
# Define the settings for returns computation
returns_compute_settings = {'return_type': 'LOG', 'freq': 1}
# Compute returns from price data
returns_dict = utils.calculate_returns(
data_path,
regime_dict,
returns_compute_settings
)
...
# Define the settings for scenario generation
scenario_generation_settings = {
'num_scen': 20000, # Number of return scenarios to simulate
'fit_type': 'kde',
'kde_settings': {'bandwidth': 0.01,
'kernel': 'gaussian',
'device': 'GPU'
},
'verbose': False
}
# Generate return scenarios from KDE
sp500_returns_dict = cvar_utils.generate_cvar_data(
returns_dict,
scenario_generation_settings
)
值得注意的是,与 CPU 相比,使用 cuML 通过 GPU 加速进行 KDE 拟合和采样可带来显著的性能提升,尤其在数据集规模增大以及采样场景数量增加的情况下更为明显。图 3 展示了 cuML 在 GPU 加速下的直接对比结果,反映了随着计算需求上升,CPU 与 GPU 所需时间的比值变化。
GPU:NVIDIA H200;CPU:英特尔至强 Platinum 8480+ 处理器
第 2 步:优化设置
以下参数用于设定均值-条件风险价值(Mean-CVaR)投资组合优化问题:
# Define CVaR optimization parameters for the S&P 500 example
sp500_cvar_params = CvarParameters(
#Asset weight allocation bounds
w_min={'NVDA':0.1, 'others': -0.3}, w_max={'NVDA':0.6, 'others':0.4},
c_min=0.0, c_max=0.2, # Cash holdings bounds
L_tar=1.6, # Leverage
T_tar=None, # Turnover (None for this example)
cvar_limit=None, # Hard limit on CVaR (None = unconstrained)
cardinality = None, # Max number of assets allowed in the portfolio
risk_aversion=1.0, # Risk aversion level
confidence=0.95, # CVaR confidence level
)
所有优化参数均支持自定义。例如,您可以通过在字典中设定各资产的代码及其对应的权重限制,来调整投资组合中每个资产的集中度。此外,您还可以调节风险规避水平——风险规避程度越高,通常会使投资组合的风险分布更加分散。最后,通过引入基数约束,可控制最终投资组合中所包含的资产数量。
然后,结合第 1 步返回的数据和问题参数,对问题进行表述。
# Instantiate CVaR optimization problem for the S&P 500 example
sp500_cvar_problem = cvar_optimizer.CVaR(
returns_dict=sp500_returns_dict,
cvar_params=sp500_cvar_params
)
第 3 步:求解
接下来,调用 cuOpt LP 求解器以获取优化的产品组合。您还可以为该求解器提供自定义配置,例如求解模式、精度等参数。更多详细信息请参考 cuOpt 官方文档。
对于此示例,采用 cuOpt PDLP 的默认容差 1e-4。默认情况下,cuOpt 会并行执行 PDLP、屏障法和双单纯形法,whichever 方法最先完成,即返回其解。
# GPU solver settings
gpu_solver_settings = {"solver": cp.CUOPT,
"verbose": False,
"solver_method": "Concurrent",
"time_limit":15,
"optimality": 1e-4
}
# Solve on GPU
gpu_results, gpu_portfolio = cvar_problem.solve_optimization_problem(solver_settings=gpu_solver_settings)
在给定的约束条件和风险规避水平下,对包含397只股票的投资组合进行优化,选出12只股票建立多头头寸,同时选择2只股票建立空头头寸。随后需验证优化后的投资组合是否满足所有设定的限制条件。
============================================================
CVaR OPTIMIZATION RESULTS
============================================================
PROBLEM CONFIGURATION
------------------------------
Solver: CUOPT
Regime: recent
Time Period: 2021-01-01 to 2024-01-01
Scenarios: 20,000
Assets: 397
Confidence Level: 95.0%
PERFORMANCE METRICS
------------------------------
Expected Return: 0.002537 (0.2537%)
CVaR (95%): 0.025700 (2.5700%)
Objective Value: -0.001396
SOLVING PERFORMANCE
------------------------------
Setup Time: 0.4921 seconds
Solve Time: 0.3685 seconds
OPTIMAL PORTFOLIO ALLOCATION
------------------------------
PORTFOLIO: CUOPT_OPTIMAL
----------------------------------------
Period: 2021-01-01 to 2024-01-01
LONG POSITIONS (12 assets)
-------------------------
LLY 0.326 ( 32.64%)
NVDA 0.151 ( 15.11%)
MCK 0.136 ( 13.60%)
IT 0.101 ( 10.13%)
IRM 0.098 ( 9.84%)
JBL 0.097 ( 9.71%)
PWR 0.083 ( 8.25%)
STLD 0.070 ( 6.96%)
COP 0.056 ( 5.64%)
FICO 0.043 ( 4.28%)
MRO 0.021 ( 2.07%)
NUE 0.018 ( 1.78%)
Total Long 1.200 (120.01%)
SHORT POSITIONS (2 assets)
--------------------------
MTCH -0.248 (-24.85%)
ILMN -0.148 (-14.82%)
Total Short -0.397 (-39.67%)
CASH & SUMMARY
--------------------
Cash 0.200 ( 20.00%)
Residual 0.000 ( 0.01%)
Net Equity 0.803 ( 80.33%)
Total Portfolio 1.003 (100.35%)
Gross Exposure 1.597 (159.68%)
----------------------------------------
============================================================
开发者示例简化了求解器的调用过程,使用户能够方便地使用任意求解器。通过调整求解器配置,无需修改代码即可切换不同的求解器。例如,若要对比 CPU 求解器的性能,只需声明一个新的求解器即可。
solver_settings = {'solver': "CUSTOM_SOLVER", 'verbose': False}
#solve the optimization problem using an open-source CPU solver
cpu_results, cpu_portfolio = cvar_problem.solve_optimization_problem(solver_settings)
表 1 对比了 cuOpt 求解器与先进的开源 CPU 求解器的性能,测试问题包含 20796 个变量和 20796 个约束条件,约束矩阵中约有 800 万个非零元素。两个求解器的最优性容差均设为 1e-4,对于 cuOpt,选用 PDLP 求解方法。
cuOpt 求解器在 NVIDIA H200 GPU 上运行,而 CPU 求解器则基于英特尔至强 Platinum 8480* 处理器。相比 CPU 求解器,cuOpt LP 求解器表现出更优的性能,可将求解时间从几分钟缩短至亚秒级。
| CPU Solver(秒) | GPU Solver(秒) | GPU加速比(相对于CPU) 时期 |
|
| 时期 | 求解时间(秒) | 求解时间(秒) | X |
| Pre-crisis (“2005-01-01”,“2007-10-01”) |
70.36 | 0.53 | 131.7 |
| 危机时期 (“2007-10-01”,“2009-04-01”) |
42.19 | 0.92 | 45.8 |
| 后危机时期 (“2009-06-30”,“2014-06-30”) |
75.50 | 0.45 | 167.4 |
| 石油价格崩溃时期 (“2014-06-01”,“2016-03-01”) |
53.43 | 0.51 | 105.6 |
| FAANG时期 (“2015-01-01”,“2021-01-01”) |
49.89 | 0.73 | 68.0 |
| 新冠疫情时期 (“2020-01-01”,“2023-01-01”) |
57.43 | 0.66 | 86.5 |
| 近期 (“2022-01-01”,“2024-07-01”) |
56.32 | 0.56 | 99.5 |
2 万个场景,397 种素材,GPU 采用 NVIDIA H200,CPU 采用英特尔至强 Platinum 8480 或更高型号。
高效前沿是一组最优投资组合,能够在特定风险水平下提供最高的预期回报,或在既定预期回报下实现最低的风险。为确定高效前沿,需针对不同的风险偏好程度,求解一系列优化问题。
例如,在图 4 中,生成了包含 50 个具有不同风险规避水平的高效投资组合的前沿曲线。4 倍速视频显示,相较于使用 CPU 求解器进行实时求解,cuOpt GPU 求解器在生成该前沿曲线时速度显著更快。
第 4 步:回测
最后,可对优化后的投资组合进行回测,并评估一些关键指标,如累积收益、夏普比率和最大回撤。在以下示例中,系统将启动回测模块,对比优化投资组合与等权重投资组合的表现(即在每个可投资产上分配相同权重)。
from src import backtest
# Create backtester and run backtest
backtester = backtest.portfolio_backtester(gpu_portfolio, test_returns_dict, risk_free, test_method, benchmark_portfolios = None)
backtest_result,_ = backtester.backtest_against_benchmarks(plot_returns=True, cut_off_date=cut_off_date)
在回测期间,虚线表示开始进行样本外测试,此后优化后的投资组合表现持续优于等权重基准,并实现了更高的收益。
动态平衡
动态再平衡至关重要,因为原本适宜的投资组合会随着市场环境的变化而逐渐偏离预期状态——预期收益分布具有非平稳性。与维持固定配置不同,基于触发机制的再平衡(例如根据投资组合价值波动或资产权重偏离)能够及时调整风险敞口,增强对下行风险的抵御能力,并使投资组合持续符合预设的风险预算。
这需要反复进行重新优化。探索不同的再平衡策略通常涉及数百次迭代,随着迭代次数增加,优化所需时间也随之上升。因此,快速且准确的求解器至关重要:在量化投资组合优化示例中,开发者可在几分钟内完成这些任务,而使用传统CPU求解器则可能需要数小时甚至数天。
例如,在2022年7月1日至2024年5月1日期间,对两种策略(价值变动百分比与分配漂移)进行比较,采用买入并持有策略。投资组合每三个月(即63个交易日)进行一次回测,当监控指标超过预设阈值时,将触发重新优化。
在图6中,当投资组合价值自上次上涨以来累计下跌0.5%时,便会触发再平衡操作。在此期间,该策略共触发了4次再平衡,实现了15.6%的总回报,表现优于买入持有策略。
图8展示了对不同策略的测试结果。当投资组合的当前结构偏离初始配置时,系统将触发再平衡。随着市场价格的变动,资产权重可能发生波动,导致投资组合不再满足预设的约束条件,因此有必要基于最新的市场数据重新进行优化。同时,再平衡策略有助于保持投资组合的市场竞争力,并实现持续的正向回报。
投资组合优化是一项持续进行的核心任务,而非一次性工作——cuOpt 所提供的单次优化加速,在高频交易环境中将产生显著的累积效应。此外,策略可能更加复杂,涉及更多超参数,而探索最优策略需要反复执行上述过程。换句话说,这些示例策略主要突出 GPU 加速的优势,并未针对实际部署进行充分调优。为了找到更优策略,仍需开展大量优化迭代。
开始优化投资组合
工作流程的执行速度取决于最慢的环节。通过将数据准备、场景生成和求解过程迁移至 GPU,量化投资组合优化的开发者示例有效消除了常见瓶颈,将求解时间从几分钟甚至几小时缩短至几秒钟。在需要反复执行的工作流程中——如再平衡、参数空间扫描、压力测试和回测——通常涉及数百次的重新优化,因此整体效率显著提升。
借助用于线性规划求解的 cuOpt,以及用于预处理和模拟的 CUDA-X DS,您可以提升迭代频率,测试更复杂的约束条件,并近乎实时地响应市场变化。这不仅加快了洞察获取的速度,还支持更高效地大规模应用基于 CVaR™ 的风险模型,并探索动态再平衡的可行路径。量化投资组合优化开发者示例将大规模、风险感知的投资组合优化转变为一种交互式能力,而非繁琐的批量任务。
借助 GPU 加速,推动投资组合优化的转型升级,实现实时运行复杂的风险模型与资产配置。提升洞察速度,增强系统可扩展性,助力构建更智能的数据驱动型投资策略。
访问 build.nvidia.com,获取 GitHub 上的量化投资组合优化 Notebook,并在 NVIDIA Brev 或您自有的云基础设施上,部署于 GPU 加速环境中运行。