我正在研究一个Python脚本,该脚本将有助于年度投资组合的重新平衡。对于那些不熟悉该概念的人来说,它基本上意味着每年购买/出售具有增值/亏损值的资产,以便您的投资组合组成实际上与所需的资产分配相匹配。如果在1月1日,您的投资组合的股票/债券比例为50/50,并且股市表现出色,那么到同年12月31日,您的投资组合中的股票将超重,这意味着您将需要卖出一些股票来购买债券,以使分配比例回到50/50。如果所有资产都在一个账户中,那么如何做到这一点很容易,但是如果您在多个账户中进行投资,则可能会变得很复杂,尤其是如果这些账户是退休账户,而您不应该在退休年龄之前退出的话。
对于再平衡步骤,我建立了一个由8个简单线性方程式组成的系统。它们大致如下所示(请参见第二代码块中的增强矩阵):
Asset1 + Asset2 + ... = us_bonds_target
Asset1 + Asset2+ ... = total_401k_value
...and so on
然后我以以下方式使用Sympy的resolve_linear_system函数:
from sympy import Matrix, symbols, solve_linear_system
Assets_Matrix = Matrix([[1, 0, 0, 0, 1, 0, 0, 1, 9571165],
[0, 1, 0, 0, 0, 0, 0, 0, 7298011],
[0, 0, 0, 1, 0, 0, 0, 0, 4665941],
[0, 0, 1, 0, 0, 1, 0, 0, 7178371],
[0, 0, 0, 0, 0, 0, 1, 0, 7178371],
[1, 1, 1, 1, 0, 0, 0, 0, 22550494],
[0, 0, 0, 0, 1, 0, 0, 0, 7200311],
[0, 0, 0, 0, 0, 1, 1, 1, 6141054]])
Asset1, Asset2, Asset3, Asset4, Asset5, Asset6, Asset7, Asset8 = symbols('Asset1, Asset2, Asset3, Asset4, Asset5, Asset6, Asset7, Asset8', nonnegative = True)
solution = solve_linear_system(Assets_Matrix, Asset1, Asset2, Asset3, Asset4, Asset5, Asset6, Asset7, Asset8)
运行此代码将产生如下输出:
{Asset5: 7200311,
Asset6: -Asset8 - 1037317,
Asset7: 7178371,
Asset3: Asset8 + 8215688,
Asset4: 4665941,
Asset2: 7298011,
Asset1: -Asset8 + 2370854}
这与我想要的非常接近,这是资产列表及其重新平衡的目标值。但是,有一些限制:
有时它会带给我负面的解决方案,在这种情况下这是没有用的。现实生活中资产值不能小于0。
这是一个更大的问题:我无法在任何变量上指定约束。这些资产大多数都是共同基金,有利于为每种资产维持一定的最小值,因为如果您达成一项投资,某些共同基金具有不同的“类别”,它们的费用比率(每年持有该投资的成本是多少)会较低。最低。对于这些资产中的大多数,我希望每笔投资不少于1万美元。我意识到有时这会导致系统无法解决,但是我至少想先尝试使用这些约束来解决它,然后在求解器失败时放宽它们。
在遍历堆栈溢出和Google之后,我了解到使用线性编程可以解决此问题。因此,我将问题设置如下(请注意,我尚未将资产的最低价值要求并入代码中(除了它们必须为正值外,我只是想证明这种方法将产生有用的解决方案)) :
from scipy.optimize import linprog
A = [[1, 0, 0, 0, 1, 0, 0, 1],
[0, 1, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0],
[1, 1, 1, 1, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 1, 1]]
B = [9571165, 7298011, 4665941, 7178371, 7178371, 22550494, 7200311, 6141054]
C = [0, 0, 0, 0, 0, 0, 0, 0]
linprog(c = C, A_eq = A, b_eq = B, bounds = (0, None), method = 'interior-point')
但是,当我运行此代码时,得到以下输出:
con: array([ 2370852.29007765, 0. , 0. ,
7178369.8786112 , 0. , 10586541.29564287,
0. , -1037319.12695402])
fun: 0.0
message: 'The algorithm terminated successfully and determined that the problem is infeasible.'
nit: 4
slack: array([], dtype=float64)
status: 2
success: False
x: array([ 3.97865052e-02, 7.29801100e+06, 6.64570623e-01,
4.66594100e+06, 7.20031100e+06, 4.56818174e-01,
7.17837100e+06, 1.67013585e+00])
由于某种原因,似乎linprog不喜欢我的方程式。我的问题是否非常适合linprog函数?如果是这样,我在做什么错?还是应该以其他方式解决这个问题?
答案 0 :(得分:1)
算法成功终止,并确定该问题不可行。
这意味着无法在约束范围内解决问题。要了解原因,让我们仔细看一下sympy结果:
Asset5: 7200311
Asset6: -Asset8 - 1037317
Asset7: 7178371
Asset3: Asset8 + 8215688
Asset4: 4665941
Asset2: 7298011
Asset1: -Asset8 + 2370854
这意味着我们可以为资产1、3、6或8中的任何一个选择任何值,而其他值是从中得出的。现在应用资产不能为负的约束。
Asset1 >= 0
到Asset8 <= 2370854
Asset3 >= 0
到Asset8 >= -8215688
Asset6 >= 0
开始,Asset8 <= -1037317
...与Asset8 >= 0
不兼容。总而言之,如果所有资产都必须为正数,则无法解决该问题。