# Hierarchical Risk Parity with allocation constraints?

In the really interesting paper by Marcos Lopez de Prado a variation of risk parity is applied whereby the underlying assets of the portfolio are first split in 'correlation clusters' and the allocation percentages are distributed based on that.

More specifically, the allocation algorithm is initially splitting the assets in two groups and assigning a variance-based allocation in these, while proceeding with a tree-like recursive procedure for the members of the two initial groups.

This results in the weights being in [0,1], however, as mentioned a couple of times in the paper, this can be easily modified so as to accommodate different constraints. Any idea on how this would be possible? For example, how can I get the weights to be in the range [0.01 0.1]?

EDITED

You are right. We have to look town to the "leaves" in each iteration. I would do it the following way:

If $L_i^{(j)}$ is the set of indices in the $j$ branch ($j \in \{1,2\}$), then we define $s_i^{(j)}=\sum_{n \in L_i^{(j)}w_n}$, the weight of the branch before scaling and $n_i^{(j)}=\left|L_i^{(j)}\right|$ the number of leaves in the branch.

The box constraints for the weights we call $w_\text{min}$ and $w_\text{max}$.

Let $\alpha_i$ be the scaling factor for $L_i^{(1)}$ and $1-\alpha_i$ the scaling factor for $L_i^{(2)}$.

To fulfill the constraints, we need to check the resulting weights.

If we scale the weights of $L_i^{(j)}$ by $\alpha_i$, we must have enough room to maneuver so that the minimum weight constraint can still fit into the branch weight and we must have a limited weight in order to be able to fulfil the upper bounds:

$$\alpha_i s_i^{(1)} \geq n_i^{(1)} w_\text{min}$$ $$\alpha_i s_i^{(1)} \leq n_i^{(1)} w_\text{max}$$

For the other side of the branch, we need to check, the analogue thing:

$$(1-\alpha_i) s_i^{(2)} \geq n_i^{(2)} w_\text{min}$$ $$(1-\alpha_i) s_i^{(2)} \leq n_i^{(2)} w_\text{max}$$

If we put all four of them together, we get the following inequalities for $\alpha_i$:

$$\text{max}\left(1-\frac{n_i^{(2)}w_\text{max}}{s_i^{(2)}},\frac{n_i^{(1)}w_\text{max}}{s_i^{(1)}}\right) \leq \alpha_i \leq \text{min}\left(1-\frac{n_i^{(2)}w_\text{min}}{s_i^{(2)}},\frac{n_i^{(1)}w_\text{max}}{s_i^{(1)}}\right)$$

So if we define the lower bound as $\text{LB}_i$ and the upper bound as $\text{UB}_i$, we adjust the scaling factor as follows:

$$\hat{\alpha}_i = \text{max}(\text{LB}_i,\text{min}(\alpha_i,\text{UB}_i))$$

If $\text{UB}_i \leq \text{LB}_i$, then terminate the function. I hope this only happens if the constraints are incompatible but I didnt attempt a proof.

This way, you can proceed with the algorithm while fulfilling the constraints.

Linear constraints on sigle assets are probably the only useful type of constraints you can impose. Constraints on sector weights for example will be impossible here due to the clustering structure. In practice, I can see this being a big drawback.

Compared to the classical inverse volatility Risk Budgeting, this approach is really elegant, since it only ignores the part of the variance covariance matrix that is of little importance if you will.

• thanks for your comment, I can see two issues with this approach: 1. some of my assets are so volatile that currently (and after using some covariance matrix shrinkage method) under the same sub-cluster one of the assets get 0.004 weighting and the other 0.0101... somehow the algo should look forward on how many 'leaves'/assets are under each cluster and set the minimum based on this 2. If I initialize the weights to 0.1, given the fact that we start with two nodes, finally the weights will sum up to 0.2 – sen_saven Nov 28 '17 at 13:59
• OK I agree with you on the initialization, thats my mistake. We have to initialize with $1$ of course. I think we could add the maximum constraint in the scaling factor as well. That must have been the idea of the author. I 100% agree with you - the thing is neither easy nor straight forward. Looking throught to the leaves cannot be what the author had in mind. I will edit my answer and give it another try if you dont mind... – vanguard2k Nov 28 '17 at 14:23
• sure, any further ideas are welcome – sen_saven Nov 28 '17 at 14:56
• thanks for taking the time to further analyze this. As far as I understand you are suggesting a post-processing of the weights after the initial algo has run. This should probably work but I thought that the author of the paper had in mind a 'real-time' solution. In any case, I don't have any better idea either so I will try to implement something like this... will let you know if this works – sen_saven Nov 29 '17 at 13:29
• @sen_shaven No its not post-processing! In every step, you look at the scaling and just prevent it to scale it to a value thats infeasible given the constraints... (for example scale all the weights in one branch to a value smaller than number of leaves times minimum weight) – vanguard2k Nov 29 '17 at 15:11

On formula 3.c on page 8 in his paper.

We have:

$\alpha = 1 - v_1/(v_1 + v_2$)

Where a ~ (0,1), therefore $v_1$ and $v_2$ are both between (0,1) and sum to 1 as well. So we can scale both $v_1$ and $v_2$ appropriately ex:

$v^{new}_1 = (1-0.01) * v_1 + 0.01$

This would give us the desired weight range

• $v_1$ and $v_2$ are the volatilities of the clusters... (so they are not between $0$ and $1$, they also dont sum to $1$. I dont see how this relates to weights... Moreover, the maximum according to the OP should be $0.1$. – vanguard2k Nov 28 '17 at 8:32
• thanks for your response, I could apply this to the weights (while the u's are the volatilities of the cluster) but there is a for-loop there... I could apply a variation of your transformation after all the weights have been calculated but I think that this will distort the methodology – sen_saven Nov 28 '17 at 13:39
• @vanguard2k the paper suggests modifying steps 3.c-3.e perhaps I am just scaling the wrong thing? Also you can replace the 1 with the desired max i.e $(0.1 - 0.01) * v_1 + 0.01$ for the [0.01, 0.1] range – pyCthon Nov 29 '17 at 15:35