Skip to content

Commit

Permalink
Update assetalloc_2.py
Browse files Browse the repository at this point in the history
  • Loading branch information
lililiyf committed Apr 21, 2022
1 parent e3d4cbc commit 9460b6f
Showing 1 changed file with 173 additions and 40 deletions.
213 changes: 173 additions & 40 deletions pyfeng/assetalloc_2.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,32 @@
from scipy.optimize import NonlinearConstraint
import sys

sys.path.insert(0, '/Users/liyafen/Documents/GitHub/PyFENG/pyfeng')
#import pyfeng as pf
import pyfeng.ex as pfex
from assetalloc import AssetAllocABC
from .assetalloc import AssetAllocABC

class RiskParity2(AssetAllocABC):
"""
Risk parity (equal risk contribution) asset allocation with general bounds.
References:
-Bai X, Scheinberg K, Tutuncu R (2016) Least-squares approach to risk parity in portfolio selection. Quantitative Finance 16:357–376.
Examples:
>>> import numpy as np
>>> import pyfeng as pf
>>> m = pfex.RiskParity2(cov=cov)
>>> weight = m.general_risk_parity_with_fixed_theta(a=-1,b=2)
>>> print(weight)
# [0.45520246 0.4805526 0.06424494]
>>> weight = m.general_risk_parity_with_variable_theta(a=-1,b=2)
>>> print(weight)
# [0.26339982 0.19102125 0.54557893]
>>> weight = m.minimum_variance_risk_parity_extended_least_square(rho=1000, beta=0.01, tol=1e-6, itreation_max=100, a=-1,b=2)
>>> print(weight)
# [ 0.53233682 0.51447136 -0.04680817]
"""

def __init__(self, sigma=None, cor=None, cov=None, ret=None, budget=None, longshort=0):
"""
Expand All @@ -35,26 +55,129 @@ def __init__(self, sigma=None, cor=None, cov=None, ret=None, budget=None, longsh
# assert np.isclose(np.sum(budget), 1)
# self.budget = np.array(budget)

def optimization_of_convex_problem(self,x0,rho,cov_m,bnds):
def weight_general(self,x0,cov_m,bnds):
"""
Solve the optimization of convex problem for the minimum variance weight extended least square.
Solve the optimization problem for the general risk parity problem with fixed theta.
Args:
x0: weights for asset allocation problem.
cov_m: asset covariance
bnds: boundary likes (a,b), means that weight x satisfy a<=x<=b
Returns:
risk parity weight
"""

# --formula (16) --

# fix theta:
n_assets = len(x0)
rp = np.full(n_assets, 1 / n_assets)
list_bnds = []
for i in range(len(x0)):
list_bnds.append(bnds)
bnds = tuple(list_bnds)
cons = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0}]
func = lambda x: np.sum((x * (cov_m @ x) / (x.T @ cov_m @ x) - rp) ** 2 )
res = minimize(func, x0, method='SLSQP', constraints=cons,bounds=bnds, tol=1e-10)
weight = res.x
return weight

def general_risk_parity_with_fixed_theta(self,a=-1,b=2):
"""
Least-squares risk parity model with general bounds of Bai et al.(2016)
---Implementation of 2.3 formula (16)---
Args:
a: lower bound, means that weight x satisfy a<=x
b: upper bound, means that weight x satisfy x<=b
Returns:
risk parity weight
References:
-Bai X, Scheinberg K, Tutuncu R (2016) Least-squares approach to risk parity in portfolio selection. Quantitative Finance 16:357–376.
"""

# implementation of general risk parity formula with fixed theta in 2.3
bonds = (a, b)
cor = self.cor_m
cov_m = self.cov_m
x0 = np.full(self.n_asset, 1 / np.sqrt(np.sum(cor)))
return self.weight_general(x0,cov_m,bonds)


def weight_general_2(self,x0,cov_m,bnds):
"""
Solve the optimization problem for the general risk parity problem with variable theta.
Args:
x0: weights for asset allocation problem.
cov_m: asset covariance
bnds: boundary likes (a,b), means that weight x satisfy a<=x<=b
Returns:
risk parity weight
"""

# --formula (17) --

#variable theta:
n_assets = len(x0)
list_bnds = []
for i in range(n_assets):
list_bnds.append(bnds)
for i in range(n_assets):
list_bnds.append((None, None))
bnds = tuple(list_bnds)

cons = [{'type': 'eq', 'fun': lambda x: np.sum(x[:int(len(x) / 2)]) - 1.0}]
rp = np.full(n_assets, 1 / n_assets)
rp = (x0.T @ cov_m @ x0) * rp

func = lambda x: np.sum(
(x[:int(len(x) / 2)] * (cov_m @ x[:int(len(x) / 2)]) - x[int(len(x) / 2):]) ** 2)

res = minimize(func, [x0, rp], method='SLSQP', constraints=cons, bounds=bnds, tol=1e-10)
weight = res.x[:int(len(res.x) / 2)]

return weight

def general_risk_parity_with_variable_theta(self,a=-1,b=2):
"""
Least-squares risk parity model with general bounds of Bai et al.(2016)
---Implementation of 2.3 formula (17)---
Args:
a: lower bound, means that weight x satisfy a<=x
b: upper bound, means that weight x satisfy x<=b
Returns:
risk parity weight
References:
-Bai X, Scheinberg K, Tutuncu R (2016) Least-squares approach to risk parity in portfolio selection. Quantitative Finance 16:357–376.
"""
# implementation of general risk parity formula with variable theta in 2.3
bonds = (a, b)
cor = self.cor_m
cov_m = self.cov_m
x0 = np.full(self.n_asset, 1 / np.sqrt(np.sum(cor)))
return self.weight_general_2(x0, cov_m, bonds)

def weight_minimum_variance(self,x0,rho,cov_m,bnds):
"""
Solve the optimization problem for the minimum variance weight extended least square.
Args:
x: weights for asset allocation problem.
x0: weights for asset allocation problem.
rho: the weight parameter of the convex term in the formula.
cov_m:
bnds: boundary likes (a,b)
cov_m: asset covariance
bnds: boundary likes (a,b), means that weight x satisfy a<=x<=b
Returns:
risk parity weight
"""
#fix theta:
# list_bnds = []
# for i in range(len(x0)):
# list_bnds.append(bnds)
# bnds = tuple(list_bnds)
# cons = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1.0}]
# rp = [0.2,0.2,0.2,0.2,0.2]
# func = lambda x: np.sum((x * (cov_m @ x) / (x.T @ cov_m @ x) - rp) ** 2 + rho*(x.T @ cov_m @ x))
# res = minimize(func, x0, method='SLSQP', constraints=cons,bounds=bnds, tol=1e-10)
# weight = res.x

# --formula (28) --

Expand All @@ -78,48 +201,41 @@ def optimization_of_convex_problem(self,x0,rho,cov_m,bnds):

return weight

def minimum_variance_weight_extended_least_square(self, rho=1000, beta=0.01, tol=1e-6, itreation_max=100,a=-1,b=2):
def minimum_variance_risk_parity_extended_least_square(self, rho=1000, beta=0.01, tol=1e-6, itreation_max=100, a=-1, b=2):
"""
Minimum variance with risk parity using the Extended least-squares models of Bai et al.(2016)
---Implementation of 4.1 formula (28)---
Args:
rho: the weight parameter of the convex term in the formula.
beta: the scholar for decreasing rho.
tol: error tolerance.
itreation_max: The maximum number of times the weight is calculated
a: lower bound, means that weight x satisfy a <= x
b: upper bound, means that weight x satisfy x <= b
Returns:
risk parity weight
risk parity weight with minimum variance
References:
-Bai X, Scheinberg K, Tutuncu R (2016) Least-squares approach to risk parity in portfolio selection. Quantitative Finance 16:357–376.
"""
#Algorithm 1 in 4.1

# Algorithm 1 in 4.1
bonds = (a,b)
cor = self.cor_m
cov_m = self.cov_m
x = np.full(self.n_asset, 1 / np.sqrt(np.sum(cor)))
for k in range(0,itreation_max):
if(rho >= tol):
x = self.optimization_of_convex_problem(x,rho,cov_m,bonds)
x = self.weight_minimum_variance(x,rho,cov_m,bonds)
rho = rho * beta
else:
x = self.optimization_of_convex_problem(x, 0, cov_m,bonds)
x = self.weight_minimum_variance(x, 0, cov_m,bonds)
break
return x










if __name__ == '__main__':
import numpy as np
import pyfeng as pf

cov = np.array([
[94.868, 33.750, 12.325, -1.178, 8.778],
[33.750, 445.642, 98.955, -7.901, 84.954],
Expand All @@ -128,20 +244,37 @@ def minimum_variance_weight_extended_least_square(self, rho=1000, beta=0.01, tol
[8.778, 84.954, 45.184, 1.057, 34.126]
]) / 10000


m = RiskParity2(cov=cov)
weight = m.minimum_variance_weight_extended_least_square(rho=1000, beta=0.01, tol=1e-6, itreation_max=100,a=-1,b=2)

weight = m.general_risk_parity_with_fixed_theta()
print(weight)
#[ 0.05027209 0.00553736 -0.01230498 0.85650904 0.09998649]
# [0.12450587 0.04666161 0.08328325 0.61329749 0.13225179]

weight = m.general_risk_parity_with_variable_theta()
print(weight)
# [0.20003216 0.19990448 0.20002062 0.20001948 0.20002326]

weight = m.minimum_variance_risk_parity_extended_least_square(rho=1000, beta=0.01, tol=1e-6, itreation_max=100,a=-1,b=2)
print(weight)
# [ 0.05027209 0.00553736 -0.01230498 0.85650904 0.09998649]

cov = np.array([
[1,-0.9,0.6],
[-0.9,1.0,-0.2],
[0.6,-0.2,4.0]
])

m = RiskParity2(cov=cov)
weight = m.minimum_variance_weight_extended_least_square(rho=1000, beta=0.01, tol=1e-6, itreation_max=100, a=-1,
b=2)

weight = m.general_risk_parity_with_fixed_theta(a=-1,b=2)
print(weight)
# [0.45520246 0.4805526 0.06424494]

weight = m.general_risk_parity_with_variable_theta(a=-1,b=2)
print(weight)
# [0.26339982 0.19102125 0.54557893]

weight = m.minimum_variance_weight_extended_least_square(rho=1000, beta=0.01, tol=1e-6, itreation_max=100, a=-1,b=2)
print(weight)
#[ 0.53233682 0.51447136 -0.04680817]
# [ 0.53233682 0.51447136 -0.04680817]

0 comments on commit 9460b6f

Please sign in to comment.