8

He aquí un acertijo interesante.optimización quadprog

A continuación se muestra un R snippet que identifica el punto de tangencia de una función cuadrática con respecto a una línea dibujada desde el punto (0, rf) en el eje y.

Para aquellos que están familiarizados con la teoría de la cartera, este punto es a cambio y el espacio de riesgo y la solución es un conjunto de pesos que definen la cartera de tangencia (relación máxima de afilado). El fragmento permite pesos negativos (es decir, shorts) y hay una restricción de peso igualdad que requiere la suma de los pesos = 1.

require(quadprog) 

# create artifical data 
nO  <- 100  # number of observations 
nA  <- 10  # number of assets 
mData <- array(rnorm(nO * nA, mean = 0.001, sd = 0.01), dim = c(nO, nA)) 
rf  <- 0.0001  # riskfree rate (2.5% pa) 
mu  <- apply(mData, 2, mean) # means 
mu2 <- mu - rf     # excess means 

# qp 
aMat <- as.matrix(mu2) 
bVec <- 1 # set expectation of portfolio excess return to 1 
zeros <- array(0, dim = c(nA,1)) 
solQP <- solve.QP(cov(mData), zeros, aMat, bVec, meq = 1) 

# rescale variables to obtain weights 
w <- as.matrix(solQP$solution/sum(solQP$solution)) 

# compute sharpe ratio 
SR <- t(w) %*% mu2/sqrt(t(w) %*% cov(mData) %*% w) 

Mi pregunta - cómo adaptar el código para resolver el conjunto óptimo de ponderaciones tales que la suma de ponderaciones se sume a un número arbitrario (incluido el caso de esquina de una cartera autofinanciada donde la suma de ponderaciones = 0) en oposición a la unidad?

Alternativamente, podría considerar agregar un elemento 'efectivo' a la matriz de covarianza con varianza-covarianza de 0, y agregar una restricción de igualdad que requiera el peso en efectivo = 1. Sin embargo, esta matriz no sería positiva semi-definida . También sospecho que los pesos no monetarios podrían ser trivialmente cero.

+1

Dentro de su llamada 'solveQP', no veo una restricción que obligue a los pesos a sumar uno. En cambio, 'aMat, bVec, meq = 1' requiere que el exceso de su cartera sea uno, que puede verificar con' sum (aMat * solQP $ solution) '. Dentro de tu llamada 'solve.QP', ¿no deberías estar usando un vector de unos en lugar de' aMat'? – flodel

+0

@flodel - estás en lo correcto. Typo arreglado, buena captura –

Respuesta

7

Primero expliquemos por qué este realmente produce la cartera máxima de Sharpe ratio.

Queremos w para maximizar w' mu/sqrt(w' V w). Pero esa cantidad no varía si multiplicamos por un número w (que es "homogénea de grado 0"): podemos, por tanto, imponer w' mu = 1, y el problema de maximizar 1/sqrt(w' V w) es equivalente a minimizar w' V w. La cartera máxima de Sharpe ratio no es única: forman una línea. Si queremos que los pesos suman hasta 1 (o cualquier otro número que no sea cero), solo tenemos que volver a escalarlos.

Si queremos que los pesos en suma a 0, podemos añadir que la restricción al problema - sólo funciona porque la restricción también es homogénea de grado 0. Usted todavía tendrá que cambiar la escala de los pesos, por ejemplo, para ser 100% largo y 100% corto.

solQP <- solve.QP(cov(mData), zeros, 
    cbind(aMat,1), 
    c(bVec,0), 
    meq = 2 
) 

# Let us compare with another solver 
V <- cov(mData) 
library(Rsolnp) 
r <- solnp(
    rep(1/length(mu), length(mu)), 
    function(w) - t(w) %*% mu2/sqrt(t(w) %*% V %*% w), 
    eqfun = function(w) sum(w), 
    eqB = 0, 
    LB = rep(-1, length(mu)) 
) 
solQP$solution/r$pars # constant 
1

Mirando el enlace que ha incluido. Aparentemente, el rol de aMat, bVec, meq = 1 dentro de la llamada solve.QP es fijar el valor del numerador (su retorno) en la fórmula de relación de Sharpe, por lo que la optimización se centra en minimizar el denominador. En cierto sentido, es perfectamente legal arreglar el numerador, es como arreglar el tamaño total de su cartera. Su cartera puede ampliarse o reducirse posteriormente, mantendrá la misma relación de Sharpe. Para ayudarlo a darse cuenta, puede ejecutar su código anterior para cualquier valor de bVec (concedido, distinto de cero) y obtendrá el mismo resultado para los pesos w y la relación de Sharpe SR.

Por lo tanto, creo que podría malinterpretar la noción de "pesos de cartera". Son ratios que representan de lo que está hecha su cartera, y deben sumar a uno. Una vez que haya encontrado los pesos óptimos, que ya hizo, puede escalar su cartera al nivel que desee, simplemente multiplique w por el valor actual que desee para su cartera.

0

Esta no es una buena técnica para las carteras largas.Incluso las carteras que pueden tener acciones cortas tienen pesos de asignaciones del signo incorrecto después de la normalización por la suma de pesos.

Estas situaciones surgen con rendimientos excesivos negativos. Forzando w'mu = 1 pone la solución a la izquierda del origen (riesgo negativo) en estos casos.

library(quadprog) 
nA = 2 # two assets 
mu2 = c(-.1,.1) # one negative excess return 
Dmat = matrix(c(1,0,0,10),2,2) 

aMat <- as.matrix(mu2) 
bVec <- 1 # set expectation of portfolio excess return to 1 
zeros <- array(0, dim = c(nA,1)) 
solQP <- solve.QP(Dmat, zeros, aMat, bVec, meq = 1) 

rawW = solQP$solution 
cat('\nraw weights ') 
cat(rawW) 

netW = rawW/sum(rawW) 
cat('\nnormalized weights ') 
cat(netW) 

portfReturn = sum(netW*mu2) 
cat('\nportfolio excess return ') 
cat(portfReturn)