Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feature request: Relaxed Risk Parity #21

Closed
ghost opened this issue Jun 18, 2021 · 7 comments
Closed

feature request: Relaxed Risk Parity #21

ghost opened this issue Jun 18, 2021 · 7 comments

Comments

@ghost
Copy link

ghost commented Jun 18, 2021

Hi, this is an amazing library! I have a small feature request: Risk Return Trade-Off Relaxed Risk Parity Portfolio Optimization, which might be an interesting addition to your library. Please let me know what you think, and if its possible to be implemented in your library. I have written some simple code for this although its not in your library's style, but I am happy to put it here to help in any way if you want to implement this paper :)

@dcajasn
Copy link
Owner

dcajasn commented Jun 18, 2021

Hi @blenderben2

Thanks for your support. First let me read the paper and related papers to know if this model can be posed as a DCP problem, after a fast read, I think it can be posed using SOCP or POWER CONE, but It could take me some time to check the maths (with the maths make the implementations is very fast). Now I'm working on adding a feature to limit the number of assets and also on a pro version of this library that include some backtest capabilities and a GUI for non programer users to finance the developed of this open source library.

Best,
Dany

@ghost
Copy link
Author

ghost commented Jun 19, 2021

Glad to hear that it is possible to be implemented. Here is my source code that I done awhile back, it was part of an implementation with cvxpylayers, but I hope it can be useful in a way for you. Oh and all the best with your pro version! :)

Σ = cp.Parameter((n_assets, n_assets))
Σ_sqrt = cp.Parameter((n_assets, n_assets))
μ = cp.Parameter(n_assets)
R = cp.Parameter(n_assets, nonneg=True)
Θ = cp.diag(cp.diag(Σ_sqrt))
        
assert penalty >= 0, 'Penalty, λ, term must be greater or equal than 0, ideally between 0 to (not far after) 1'
λ = cp.Constant(penalty) # penalty, λ
# λ = cp.Parameter(1, nonneg=True)

x = cp.Variable(n_assets)
ζ = cp.Variable(n_assets)
ψ = cp.Variable()
γ = cp.Variable()
ρ = cp.Variable(nonneg=True) # regulating-term, ρ

objective = cp.Minimize(ψ - γ)

constraint_soc1 = [ζ[i] == (Σ @ x)[i] for i in range(n_assets)] # ζ == Σ @ x
constraint_soc2 = [cp.quad_over_lin(γ, x[i]) <= ζ[i] for i in range(n_assets)] # x * ζ >= γ ** 2
constraint_soc3 = [ζ[i] >= 0 for i in range(n_assets)] # ζ >= 0 # redundant
constraint_soc4 = [x[i] >= 0 for i in range(n_assets)] # x >= 0 # redundant

constraint_soc5 = [x[i] <= max_weight for i in range(n_assets)] # personally added constraint

constraint_soc = constraint_soc1 + constraint_soc2 + constraint_soc3 + constraint_soc4 + constraint_soc5

constraint_other = [cp.quad_over_lin(Σ_sqrt @ x, (ψ + ρ)) <= n_assets * (ψ - ρ),
                    λ * cp.quad_over_lin(Θ @ x, ρ) <= ρ, 
                    # use λ.value when parameter: λ.value * cp.quad_over_lin(Θ @ x, ρ) <= ρ,
                    μ.T @ x >= R,
                    cp.sum(x) == 1, ψ >= 0, γ >= 0] # redundant (ψ >= 0)

constraint_all = constraint_other + constraint_soc

prob = cp.Problem(objective, constraint_all)

assert prob.is_dcp()
assert prob.is_dpp()

cvxpylayer = CvxpyLayer(prob, parameters=[Σ, Σ_sqrt, μ, R], variables=[x, ζ, ψ, γ, ρ])

@uhasan1
Copy link

uhasan1 commented Aug 10, 2021

Hi, this is an amazing library! I have a small feature request: Risk Return Trade-Off Relaxed Risk Parity Portfolio Optimization, which might be an interesting addition to your library. Please let me know what you think, and if its possible to be implemented in your library. I have written some simple code for this although its not in your library's style, but I am happy to put it here to help in any way if you want to implement this paper :)

Great read!!

@uhasan1
Copy link

uhasan1 commented Aug 10, 2021

Glad to hear that it is possible to be implemented. Here is my source code that I done awhile back, it was part of an implementation with cvxpylayers, but I hope it can be useful in a way for you. Oh and all the best with your pro version! :)

Σ = cp.Parameter((n_assets, n_assets))
Σ_sqrt = cp.Parameter((n_assets, n_assets))
μ = cp.Parameter(n_assets)
R = cp.Parameter(n_assets, nonneg=True)
Θ = cp.diag(cp.diag(Σ_sqrt))
        
assert penalty >= 0, 'Penalty, λ, term must be greater or equal than 0, ideally between 0 to (not far after) 1'
λ = cp.Constant(penalty) # penalty, λ
# λ = cp.Parameter(1, nonneg=True)

x = cp.Variable(n_assets)
ζ = cp.Variable(n_assets)
ψ = cp.Variable()
γ = cp.Variable()
ρ = cp.Variable(nonneg=True) # regulating-term, ρ

objective = cp.Minimize(ψ - γ)

constraint_soc1 = [ζ[i] == (Σ @ x)[i] for i in range(n_assets)] # ζ == Σ @ x
constraint_soc2 = [cp.quad_over_lin(γ, x[i]) <= ζ[i] for i in range(n_assets)] # x * ζ >= γ ** 2
constraint_soc3 = [ζ[i] >= 0 for i in range(n_assets)] # ζ >= 0 # redundant
constraint_soc4 = [x[i] >= 0 for i in range(n_assets)] # x >= 0 # redundant

constraint_soc5 = [x[i] <= max_weight for i in range(n_assets)] # personally added constraint

constraint_soc = constraint_soc1 + constraint_soc2 + constraint_soc3 + constraint_soc4 + constraint_soc5

constraint_other = [cp.quad_over_lin(Σ_sqrt @ x, (ψ + ρ)) <= n_assets * (ψ - ρ),
                    λ * cp.quad_over_lin(Θ @ x, ρ) <= ρ, 
                    # use λ.value when parameter: λ.value * cp.quad_over_lin(Θ @ x, ρ) <= ρ,
                    μ.T @ x >= R,
                    cp.sum(x) == 1, ψ >= 0, γ >= 0] # redundant (ψ >= 0)

constraint_all = constraint_other + constraint_soc

prob = cp.Problem(objective, constraint_all)

assert prob.is_dcp()
assert prob.is_dpp()

cvxpylayer = CvxpyLayer(prob, parameters=[Σ, Σ_sqrt, μ, R], variables=[x, ζ, ψ, γ, ρ])

Blenderben2 -- thanks for posting. Would you consider contributing some time to turn this into a quick Jupyter NB with comments? Would really appreciate that very much.

@dcajasn
Copy link
Owner

dcajasn commented Sep 3, 2021

Hi @blenderben2,

I've finally had time to try the relaxed risk parity. It works like in the paper, however, the model concentrate portfolio weights in assets with the higher expected (mean) returns and keep other weights equal. Due this behavior, I try another approach and I find a generalized form to include returns constraints in risk parity models. Comparing both models, I find that the new approach get lower risk than the relaxed risk parity with the same return constraint. I'm going to write a small working paper about the new approach (that works for all risk measures) before I implement both models in Riskfolio-Lib. I hope for the end of september or first week of octuber, I will add this feature to Riskfolio-Lib. As an example of both models, here are some plots:

Original Relaxed Risk Parity
Expected return: 0.18505469
Expected risk (std. dev.): 0.12813528781895778
image
image

New General Approach:
Expected return: 0.18505469
Expected risk (std. dev.): 0.12433758127346449
image
image

Best,
Dany

@ghost
Copy link
Author

ghost commented Sep 7, 2021

Thanks @dcajasn , looking forward to see the results.

Sorry @uhasan1 , but the code is quite self-explanatory if you understand the paper, and its quite similar to the equations listed in the paper

@dcajasn
Copy link
Owner

dcajasn commented Oct 11, 2021

Hi @blenderben2, I implement models A, B and C of relaxed risk parity model in version 2.0.0. Try to update Riskfolio-Lib to last version.

@dcajasn dcajasn closed this as completed Dec 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants