gpt4 book ai didi

python - 使用分组边界的 SciPy 优化

转载 作者:太空狗 更新时间:2023-10-30 03:03:39 27 4
gpt4 key购买 nike

我正在尝试执行投资组合优化,以返回最大化我的效用函数的权重。我可以很好地完成这部分,包括权重总和为 1 的约束,并且权重也给我一个目标风险。我还包括了 [0 <= 权重 <= 1] 的界限。此代码如下所示:

def rebalance(PortValue, port_rets, risk_tgt):
#convert continuously compounded returns to simple returns
Rt = np.exp(port_rets) - 1
covar = Rt.cov()

def fitness(W):
port_Rt = np.dot(Rt, W)
port_rt = np.log(1 + port_Rt)
q95 = Series(port_rt).quantile(.05)
cVaR = (port_rt[port_rt < q95] * sqrt(20)).mean() * PortValue
mean_cVaR = (PortValue * (port_rt.mean() * 20)) / cVaR
return -1 * mean_cVaR

def solve_weights(W):
import scipy.optimize as opt
b_ = [(0.0, 1.0) for i in Rt.columns]
c_ = ({'type':'eq', 'fun': lambda W: sum(W) - 1},
{'type':'eq', 'fun': lambda W: sqrt(np.dot(W, np.dot(covar, W))\
* 252) - risk_tgt})
optimized = opt.minimize(fitness, W, method='SLSQP', constraints=c_, bounds=b_)

if not optimized.success:
raise BaseException(optimized.message)
return optimized.x # Return optimized weights


init_weights = Rt.ix[1].copy()
init_weights.ix[:] = np.ones(len(Rt.columns)) / len(Rt.columns)

return solve_weights(init_weights)

现在我可以深入研究这个问题,我将我的权重存储在 MultIndex pandas 系列中,这样每个 Assets 都是对应于 Assets 类别的 ETF。打印出同等权重的投资组合时,如下所示:

出[263]:
equity       CZA     0.045455             IWM     0.045455             SPY     0.045455intl_equity  EWA     0.045455             EWO     0.045455             IEV     0.045455bond         IEF     0.045455             SHY     0.045455             TLT     0.045455intl_bond    BWX     0.045455             BWZ     0.045455             IGOV    0.045455commodity    DBA     0.045455             DBB     0.045455             DBE     0.045455pe           ARCC    0.045455             BX      0.045455             PSP     0.045455hf           DXJ     0.045455             SRV     0.045455cash         BIL     0.045455             GSY     0.045455Name: 2009-05-15 00:00:00, dtype: float64

how can I include an additional bounds requirement such that when I group this data together, the sum of the weight falls between the allocation ranges I have predetermined for that asset class?

So concretely, I want to include an additional boundary such that

init_weights.groupby(level=0, axis=0).sum()
出[264]:
equity         0.136364intl_equity    0.136364bond           0.136364intl_bond      0.136364commodity      0.136364pe             0.136364hf             0.090909cash           0.090909dtype: float64

is within these bounds

[(.08,.51), (.05,.21), (.05,.41), (.05,.41), (.2,.66), (0,.16), (0,.76), (0,.11)]

[更新]我想我会用一个我不太满意的笨拙的伪解决方案来展示我的进步。也就是说,因为它不是使用整个数据集来求解权重,而是按 Assets 类别来求解权重。另一个问题是它返回的是序列而不是权重,但我相信有人比我更合适,可以提供一些关于 groupby 函数的见解。

因此,通过对我的初始代码进行轻微调整,我得到了:

PortValue = 100000
model = DataFrame(np.array([.08,.12,.05,.05,.65,0,0,.05]), index= port_idx, columns = ['strategic'])
model['tactical'] = [(.08,.51), (.05,.21),(.05,.41),(.05,.41), (.2,.66), (0,.16), (0,.76), (0,.11)]


def fitness(W, Rt):
port_Rt = np.dot(Rt, W)
port_rt = np.log(1 + port_Rt)
q95 = Series(port_rt).quantile(.05)
cVaR = (port_rt[port_rt < q95] * sqrt(20)).mean() * PortValue
mean_cVaR = (PortValue * (port_rt.mean() * 20)) / cVaR
return -1 * mean_cVaR

def solve_weights(Rt, b_= None):
import scipy.optimize as opt
if b_ is None:
b_ = [(0.0, 1.0) for i in Rt.columns]
W = np.ones(len(Rt.columns))/len(Rt.columns)
c_ = ({'type':'eq', 'fun': lambda W: sum(W) - 1})
optimized = opt.minimize(fitness, W, args=[Rt], method='SLSQP', constraints=c_, bounds=b_)

if not optimized.success:
raise ValueError(optimized.message)
return optimized.x # Return optimized weights

下面的一行将返回稍微优化的系列

port = np.dot(port_rets.groupby(level=0, axis=1).agg(lambda x: np.dot(x,solve_weights(x))),\ 
solve_weights(port_rets.groupby(level=0, axis=1).agg(lambda x: np.dot(x,solve_weights(x))), \
list(model['tactical'].values)))

Series(port, name='portfolio').cumsum().plot()

enter image description here

[更新 2]

以下更改将返回受约束的权重,但仍然不是最优的,因为它在成分 Assets 类别上被分解和优化,因此当考虑目标风险的约束时,只有初始协方差矩阵的折叠版本可用

def solve_weights(Rt, b_ = None):

W = np.ones(len(Rt.columns)) / len(Rt.columns)
if b_ is None:
b_ = [(0.01, 1.0) for i in Rt.columns]
c_ = ({'type':'eq', 'fun': lambda W: sum(W) - 1})
else:
covar = Rt.cov()
c_ = ({'type':'eq', 'fun': lambda W: sum(W) - 1},
{'type':'eq', 'fun': lambda W: sqrt(np.dot(W, np.dot(covar, W)) * 252) - risk_tgt})

optimized = opt.minimize(fitness, W, args = [Rt], method='SLSQP', constraints=c_, bounds=b_)

if not optimized.success:
raise ValueError(optimized.message)

return optimized.x # Return optimized weights

class_cont = Rt.ix[0].copy()
class_cont.ix[:] = np.around(np.hstack(Rt.groupby(axis=1, level=0).apply(solve_weights).values),3)
scalars = class_cont.groupby(level=0).sum()
scalars.ix[:] = np.around(solve_weights((class_cont * port_rets).groupby(level=0, axis=1).sum(), list(model['tactical'].values)),3)

return class_cont.groupby(level=0).transform(lambda x: x * scalars[x.name])

最佳答案

不太确定我是否理解,但我认为您可以添加以下内容作为另一个约束:

def w_opt(W):
def filterer(x):
v = x.range.values
tp = v[0]
lower, upper = tp
return lower <= x[column_name].sum() <= upper
return not W.groupby(level=0, axis=0).filter(filterer).empty

c_ = {'type': 'eq', 'fun': w_opt} # add this to your other constraints

其中 x.range 是间隔 (tuple) 重复 K[i] 次 其中 K 是特定级别出现的次数,i 是第 i 级别。 column_name 在您的案例中恰好是一个日期。

这表示限制权重,使第 i 组中的权重总和介于关联的 tuple 区间之间。

要将每个级别名称映射到一个间隔,请执行以下操作:

intervals = [(.08,.51), (.05,.21), (.05,.41), (.05,.41), (.2,.66), (0,.16), (0,.76), (0,.11)]
names = ['equity', 'intl_equity', 'bond', 'intl_bond', 'commodity', 'pe', 'hf', 'cash']

mapper = Series(zip(names, intervals))
fully_mapped = mapper[init_weights.get_level_values(0)]
original_dataset['range'] = fully_mapped.values

关于python - 使用分组边界的 SciPy 优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18218355/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com