@@ -30,7 +30,7 @@ def __init__(self, sigma=None, cor=None, cov=None, ret=None, longshort=1):
3030 # when sigma and cor are given
3131
3232 self .sigma = np .atleast_1d (sigma )
33- self .n_asset = self .sigma . shape [ 0 ]
33+ self .n_asset = len ( self .sigma )
3434
3535 if self .n_asset == 1 :
3636 raise ValueError (f"The number of assets should be more than one." )
@@ -64,7 +64,7 @@ def __init__(self, sigma=None, cor=None, cov=None, ret=None, longshort=1):
6464 elif np .isscalar (longshort ):
6565 self .longshort = np .full (self .n_asset , np .sign (longshort ), dtype = np .int8 ) # long-only
6666 else :
67- assert self .n_asset == longshort . shape [ 0 ]
67+ assert self .n_asset == len ( longshort )
6868 self .longshort = np .sign (longshort , dtype = np .int8 ) # long-only
6969
7070
@@ -85,11 +85,20 @@ class RiskParity(AssetAllocABC):
8585 [ -1.178, -7.901, 0.503, 5.460, 1.057 ],
8686 [ 8.778, 84.954, 45.184, 1.057, 34.126 ]
8787 ])/10000
88+
8889 >>> m = pf.RiskParity(cov=cov)
8990 >>> m.weight()
9091 array([0.125, 0.047, 0.083, 0.613, 0.132])
9192 >>> m._result
9293 {'err': 2.2697290741335863e-07, 'n_iter': 6}
94+
95+ >>> m = pf.RiskParity(cov=cov, budget=[0.1, 0.1, 0.2, 0.3, 0.3])
96+ >>> m.weight()
97+ array([0.077, 0.025, 0.074, 0.648, 0.176])
98+
99+ >>> m = pf.RiskParity(cov=cov, longshort=[-1, -1, 1, 1, 1])
100+ >>> m.weight()
101+ array([-0.216, -0.162, 0.182, 0.726, 0.47 ])
93102 """
94103
95104 budget = None
@@ -111,9 +120,9 @@ def __init__(self, sigma=None, cor=None, cov=None, ret=None, budget=None, longsh
111120 if budget is None :
112121 self .budget = np .full (self .n_asset , 1 / self .n_asset )
113122 else :
114- assert self .n_asset == budget . shape [ 0 ]
123+ assert self .n_asset == len ( budget )
115124 assert np .isclose (np .sum (budget ), 1 )
116- self .budget = budget
125+ self .budget = np . array ( budget )
117126
118127 @classmethod
119128 def init_random (cls , n_asset = 10 , zero_ev = 0 , budget = False ):
@@ -137,7 +146,6 @@ def init_random(cls, n_asset=10, zero_ev=0, budget=False):
137146 m = cls (cov = cor )
138147 return m
139148
140-
141149 def weight (self , tol = 1e-6 ):
142150 """
143151 Risk parity weight using the improved CCD method of Choi and Chen (2022)
@@ -174,7 +182,6 @@ def weight(self, tol=1e-6):
174182 self ._result = {'err' : err , 'n_iter' : k }
175183 return None
176184
177-
178185 def weight_ccd_original (self , tol = 1e-6 ):
179186 """
180187 Risk parity weight using original CCD method of Griveau-Billion et al. (2013).
@@ -227,7 +234,6 @@ def _newton_jacobian(w, cov, bud):
227234 jac = cov + np .diag (bud / (w * w ))
228235 return jac
229236
230-
231237 def weight_newton (self , tol = 1e-6 ):
232238 """
233239 Risk parity weight using Newton method
@@ -238,6 +244,10 @@ def weight_newton(self, tol=1e-6):
238244
239245 Returns:
240246 risk parity weight
247+
248+ References:
249+ - Spinu, F. (2013). An Algorithm for Computing Risk Parity Weights (SSRN Scholarly Paper ID 2297383). Social Science Research Network. https://doi.org/10.2139/ssrn.2297383
250+
241251 """
242252 cor = self .cor_m
243253
0 commit comments