En muchas implementaciones de riesgo-paridad simplemente usan la regla de volatilidad inversa (es decir, los pesos son proporcionales a 1 sobre vol), y luego todos los pesos son (estrictamente) positivos por construcción.
Un número de implementaciones que hacen la optimización completa de hecho establecen la no-negatividad como una restricción explícita. Pero en general y sin tales restricciones, pueden ocurrir pesos negativos cuando igualas las contribuciones al riesgo (aunque los pesos negativos pueden ser poco probables).
Un ejemplo en R para una matriz de covarianza de 4x4, que tiene rango 4 y es definida positiva:
S <- structure(c(0.000366309632978563, -0.000105943107569848,
-0.000119667135542588, 0.000169622848883779,
-0.000105943107569848, 0.000187730511335559,
-6.49497066288097e-05, -0.000167162505503921,
-0.000119667135542588, -6.49497066288097e-05,
0.000102201079006482, 1.88829418811814e-05,
0.000169622848883779, -0.000167162505503921,
1.88829418811814e-05, 0.000208993337170307),
dim = c(4L, 4L))
La matriz de correlación implícita:
cov2cor(S)
## [,1] [,2] [,3] [,4]
## [1,] 1.000 -0.404 -0.618 0.613
## [2,] -0.404 1.000 -0.469 -0.844
## [3,] -0.618 -0.469 1.000 0.129
## [4,] 0.613 -0.844 0.129 1.000
No uso el paquete riskParityPortfolio
, pero parece que admite pesos negativos, aunque por defecto no permite que existan:
library("riskParityPortfolio")
riskParityPortfolio(S)
## $w
## [1] 0.2313 0.2990 0.4588 0.0109
##
## $relative_risk_contribution
## [1] -1.9471 -0.0858 1.5197 1.5132
## ....
riskParityPortfolio(S, w_lb = -1)
## $risk_concentration
## [1] 1.93e-14
##
## $w
## [1] -0.0829 0.4391 0.2167 0.4271
##
## $relative_risk_contribution
## [1] 0.25 0.25 0.25 0.25
## ....
Nota adicional: La matriz de covarianza de ejemplo oculta algunas dependencias bastante fuertes entre los rendimientos de los activos, que pueden no ser obvias al mirar los datos:
library("NMOF")
R <- randomReturns(na = 4, ns = 100,
sd = sqrt(diag(S)),
rho = cov2cor(S), exact = TRUE)
pairs(R)
Los cálculos basados en una matriz así (como un cálculo de riesgo marginal) suelen ser sensibles y reaccionar fuertemente a pequeños cambios ("perturbaciones") en los datos de entrada. En el ejemplo, puedes solucionar esto aumentando las iteraciones:
w <- riskParityPortfolio(S)$w
FRAPO::mrc(w, S)
## [1] -194.71 -8.58 151.97 151.32
w <- riskParityPortfolio(S, maxiter = 1e4)$w
FRAPO::mrc(w, S)
## [1] -67.3 11.2 78.2 77.9
w <- riskParityPortfolio(S, maxiter = 1e5)$w
FRAPO::mrc(w, S)
## [1] 23.1 24.7 26.1 26.1
w <- riskParityPortfolio(S, maxiter = 1e6)$w
FRAPO::mrc(w, S)
## [1] 25 25 25 25
(Uso la función de riesgo marginal mrc
del paquete FRAPO
de Bernhard Pfaff). Pero por supuesto, todo esto es el resultado de un problema empírico (no computacional): los activos están altamente correlacionados, por lo que un algoritmo siempre tendrá dificultades para diferenciar entre combinaciones lineales de esos activos.