【问题标题】:How to do Portfolio Optimization with constraints on the number of assets?如何在资产数量受到限制的情况下进行投资组合优化?
【发布时间】:2020-09-23 12:48:47
【问题描述】:

我试图在四个约束条件下最小化特定回报的波动性。

  1. 每项资产的权重都在 0 到 1 之间
  2. 所有权重之和等于 1
  3. 由资产组成的投资组合的回报等于给定的回报
  4. 最多只能使用 5 个资产中的 3 个

我尝试过用 Scipy 最小化这种方式:

cons_3 = ({'type': 'ineq', 'fun': lambda x: -np.count_nonzero(x) + 3}, 
          {'type': 'eq', 'fun': lambda x: statistics(x)[0] - tret_3}, 
          {'type': 'eq', 'fun': lambda x: np.sum(x) - 1})
x0 = [1/3, 1/3, 1/3, 0, 0]
res_3 = sco.minimize(min_func_port, x0, method='SLSQP', bounds=bnds_3, constraints=cons_3)

但显然这是不可能的。

我还了解到使用 Z3Py 是可能的,但我似乎找不到正确的编码方式。这是我目前发现的:

import pandas as pd
from z3 import *

DesiredReturn = 0.05
df = pd.DataFrame(columns=['Name', 'Return', 'Volatility'],
                  data=[['Asset_1', 0.01744, 0.694149],
                        ['Asset_2', 0.03818, 0.475544],
                        ['Asset_3', 0.08218, 0.500724],
                        ['Asset_4', 0.09818, 0.489052],
                        ['Asset_5', 0.04272, 0.706223]])

W = [Real(row.Name) for row in df.itertuples()]
Vol = Real('Vol')
Ret = Real('Ret')
s = Optimize()
s.add(And([And(w >= 0, w <= 1) for w in W]))
s.add(Sum([w for w in W]) == 1)
#Missing constraint
s.add(Ret == Sum([w * row.Return for w, row in zip(W, df.itertuples())]))
s.add(Vol == Sum([w * row.Volatility for w, row in zip(W, df.itertuples())]))
s.add(Ret == DesiredReturn)
h1 = s.minimize(Vol)
print(s.check())
print(s.model())

假设本示例中资产之间的相关性为零。

非常感谢:)

【问题讨论】:

标签: python solver z3py


【解决方案1】:

您的编码非常接近。下面是我如何编码。 (我没有安装熊猫,所以我避免使用它..)

from z3 import *

Data = [  ['Asset_1', 0.01744, 0.694149]
       ,  ['Asset_2', 0.03818, 0.475544]
       ,  ['Asset_3', 0.08218, 0.500724]
       ,  ['Asset_4', 0.09818, 0.489052]
       ,  ['Asset_5', 0.04272, 0.706223]
       ]

# Weights
W = [Real(row[0]) for row in Data]

# Return and Volatility
Ret = Sum([w * row[1] for (w, row) in zip(W, Data)])
Vol = Sum([w * row[2] for (w, row) in zip(W, Data)])

o = Optimize()

# 1. Every weight is between 0 and 1
o.add([And(w >= 0, w <= 1) for w in W])

# 2. They sum up to 1
o.add(Sum([w for w in W]) == 1)

# 3. Return is what was requested
DesiredReturn = 0.05
o.add(Ret == DesiredReturn)

# 4. Only a maximum of 3 out of the 5 assets are used
o.add(Sum([If(w == 0, 0, 1) for w in W]) <= 3)

# Want to minimize volatility
o.minimize(Vol)

r = o.check()
if r == sat:
    m = o.model()
    prec = 10
    for w in W:
         print("%s    = %s" % (w, m[w].as_decimal(prec)))
    print("Return     = %s" % m.evaluate(Ret).as_decimal(prec))
    print("Volatility = %s" % m.evaluate(Vol).as_decimal(prec))
else:
    print("solver said: %s" % r)

运行时,会打印:

Asset_1    = 0
Asset_2    = 0.803
Asset_3    = 0
Asset_4    = 0.197
Asset_5    = 0
Return     = 0.05
Volatility = 0.478205076

【讨论】:

    猜你喜欢
    • 2021-08-20
    • 2018-03-06
    • 2020-10-15
    • 2022-11-18
    • 2019-09-08
    • 1970-01-01
    • 2016-08-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多