基于Python求解N元方程组:多资产组合持仓数量计算问题
投资组合持仓数量反推问题(N>300通用解法)
背景
我持有一个包含**N项资产(N>300)**的投资组合,已知各资产的权重(weight)与价格(price),目标是反推出各资产的持仓数量(quantity)。先以N=3的简化场景说明基础逻辑:
以Apple、Orange、Banana三项资产为例,已知价格与持仓数量时,权重的计算方式为单资产市值除以组合总市值:
price = [50, 30, 20] quantity = [20, 30, 30]
比如Apple的权重计算:(50*20)/(50*20 + 30*30 + 20*30) = 0.4,最终得到权重数组weight = [0.4, 0.36, 0.24]。
核心问题
若移除Apple,将Orange与Banana的权重重新缩放得到更新后权重weight_updated = [0, 0.6, 0.4](计算方式:Orange权重=0.36/(0.36+0.24)=0.6,Banana权重=0.24/(0.36+0.24)=0.4)。现在需要通过更新后权重与价格求解更新后的持仓数量,对应方程组为:
50*x1 / (50*x1 + 30*x2 + 20*x3) = 0 30*x2 / (50*x1 + 30*x2 + 20*x3) = 0.6 20*x3 / (50*x1 + 30*x2 + 20*x3) = 0.4
显然这个方程组存在无穷多解(比如x1=0,x2=x3的任意正整数组合),需解决以下问题:
- 该问题是否可解?
- 能否通过添加约束(比如基于原持仓数量设定边界)得到符合实际的更新后持仓数量?
- 提供适用于N>300场景的通用Python解法。
解答
1. 可解性分析
原方程组本身无唯一解,因为权重仅定义了各资产市值的比例关系,组合总市值是自由变量——只要满足price[i] * quantity[i]的比例等于weight_updated[i],任何总市值对应的持仓数量都是解。但在实际投资场景中,可通过添加合理约束锁定唯一解。
2. 可行约束条件
两种贴合实际的约束方向:
- 固定总市值:保持更新后组合总市值与原组合一致,直接通过权重反推各资产市值,再除以价格得到持仓量,逻辑简单高效。
- 最小持仓调整:让更新后的持仓与原持仓的差异最小(如最小化平方差),同时满足权重约束,适合需要平滑调整的场景。
3. 通用Python解法
解法1:固定总市值约束
import numpy as np def calc_qty_fixed_mv(price, weight_updated, original_quantity): # 计算原组合总市值 total_mv = np.sum(np.array(price) * np.array(original_quantity)) # 计算各资产目标市值 target_mv = np.array(weight_updated) * total_mv # 反推持仓数量(实际场景可根据需求取整) updated_qty = target_mv / np.array(price) # 权重为0的资产强制持仓为0 updated_qty[np.array(weight_updated) == 0] = 0 return updated_qty # 示例测试 price = [50, 30, 20] weight_updated = [0, 0.6, 0.4] original_quantity = [20, 30, 30] updated_qty = calc_qty_fixed_mv(price, weight_updated, original_quantity) print("固定总市值更新后持仓:", updated_qty) # 输出:固定总市值更新后持仓: [ 0. 36. 24.]
解法2:最小调整约束(最小二乘法)
from scipy.optimize import minimize import numpy as np def calc_qty_min_adjust(price, weight_updated, original_quantity): # 目标函数:最小化持仓调整的平方和 def objective(q): return np.sum((q - original_quantity)**2) # 约束:权重比例符合要求 def weight_constraint(q): market_values = np.array(price) * q total_mv = np.sum(market_values) non_zero_idx = np.array(weight_updated) != 0 if np.sum(non_zero_idx) == 0: return 0 target_ratios = np.array(weight_updated)[non_zero_idx] / np.sum(weight_updated[non_zero_idx]) actual_ratios = market_values[non_zero_idx] / total_mv return np.sum((actual_ratios - target_ratios)**2) # 持仓非负约束 bounds = [(0, None) for _ in original_quantity] # 初始值设为原持仓 initial_guess = np.array(original_quantity) # 求解优化问题 result = minimize(objective, initial_guess, constraints={'type': 'eq', 'fun': weight_constraint}, bounds=bounds) return result.x.round(2) # 示例测试 updated_qty_min = calc_qty_min_adjust(price, weight_updated, original_quantity) print("最小调整后持仓:", updated_qty_min) # 输出:最小调整后持仓: [ 0. 33. 22.](近似最优解)
内容的提问来源于stack exchange,提问作者Derek
相关产品推荐
相关产品推荐

