3 votos

Dmat argument in solve.QP R function: ¿Cov o 2*Cov?

Antecedentes

Mi objetivo final es encontrar un portafolio ubicado en la frontera eficiente a partir de una selección de 100 acciones de un índice bursátil (por ejemplo, S&P500).

Este portafolio eficiente será tal que su varianza sea la misma que la varianza del índice bursátil. En resumen, maximizando el rendimiento para un riesgo objetivo dado.

Problema

Primero aprendí a usar el paquete PortfolioAnalytics, pero obtuve un error de la función create.efficientFrontier cada vez que pasaba el argumento type="mean-StdDev" a la función.

Sin una solución para el problema anterior, decidí usar el paquete fPortfolio. Obtuve una frontera eficiente pero no puedo obtener una matriz con los pesos, rendimientos y varianza juntos para poder hacer una búsqueda binaria en la columna de varianza y luego seleccionar los pesos correspondientes (quizás haya una forma, pero soy nuevo en R).

Sin una solución para el problema anterior, decidí ir directamente a la solución solve.QP. Finalmente pude hacer lo que quería en primer lugar.

Una vez que obtuve una frontera eficiente, decidí compararla con la que obtuve de fPortfolio. Para mi sorpresa, los resultados de varianza difieren significativamente mientras que los rendimientos son los mismos. Una vez que solucioné el problema, descubrí que la diferencia se debía al argumento Dmat, es decir, la matriz de covarianza.

Estoy pasando Dmat <- Cov * 2 a la función solve.QP pero si en cambio uso Dmat <- Cov entonces obtengo los mismos resultados de fPortfolio. Nada cambió, mismo conjunto de datos, mismas restricciones. Obviamente, la varianza de los portafolios de solve.QP es el doble de la varianza de aquellos de fPortfolio.

Estoy usando la configuración predeterminada más básica en fPortfolio, es decir, solo pasando el conjunto de datos de rendimientos a ella.

Frontera del Portafolio de MV 
 Estimador:         covEstimator 
 Solucionador:      solveRquadprog 
 Optimizar:         minRiesgo 
 Restricciones:     SóloLargo

Pregunta

Me encontré con algunos códigos en la web multiplicando la matriz de covarianza por 2 y pasando esto como Dmat. Sin embargo, algunos otros códigos simplemente pasan la matriz de covarianza como Dmat a la función solve.QP (es decir, sin multiplicarla por 2).

  • ¿Cuál enfoque es el correcto?

De mi investigación sobre la programación cuadrática y la función solve.QP, creo que la matriz de covarianza debe ser multiplicada por 2.

El procedimiento solve.QP implementa el método dual de Goldfarb e Idnani (1982, 1983) para resolver problemas de programación cuadrática de la forma min(-d^T b + 1/2 b^T D b) con las restricciones A^T b >= b_0.

La optimización de media-varianza (frontera eficiente) es un problema de programación cuadrática de la forma min(w^T D w - q R^T w) con las restricciones A^T w >= w_0.

Por lo tanto, al traducir la función objetivo de MV a la forma equivalente utilizada por solve.QP, la matriz de covarianza debe ser multiplicada por 2.

Sin embargo, esto implicaría que el código de fPortfolio es incorrecto.

  • ¿Alguien ha notado este comportamiento de fPortfolio antes?

¡Creo que estoy pasando por alto algo muy básico aquí!


Código

frontera.eficiente <- function (ret, max.asignacion=NULL, rf=0, limite.riesgo=.5, incremento.riesgo=.005)
{          
  Dmat <- 2 * cov(ret)      
  n <- ncol(Dmat)      
  Amat <- cbind(1, diag(n))
  bvec <- c(1, rep(0, n))
  meq <- 1

  if(!is.null(max.asignacion)){
    Amat <- cbind(Amat, -diag(n))
    bvec <- c(bvec, rep(-max.asignacion, n))
  }

  nCiclos <- limite.riesgo / incremento.riesgo + 1
  iCiclo <- 1

  eff <- matrix(.0, nrow=nCiclos, ncol=n+3)
  colnames(eff) <- c(colnames(returns), "Rendimiento", "DesvEst", "RazonSharpe")

  for (i in seq(from=0, to=limite.riesgo, by=incremento.riesgo))
    {
    dvec <- colMeans(ret) * i
    sol <- solve.QP(Dmat=Dmat, dvec=dvec, Amat=Amat, bvec=bvec, meq=meq)
    eff[iCiclo,"DesvEst"] <- sqrt(sum(sol$solution %*% colSums((Dmat * sol$solution))))
    eff[iCiclo,"Rendimiento"] <- as.numeric(sol$solution %*% colMeans(ret))
    eff[iCiclo,"RazonSharpe"] <- (eff[iCiclo,"Rendimiento"]-rf) / eff[iCiclo,"DesvEst"]
    eff[iCiclo,1:n] <- sol$solution
    iCiclo <- iCiclo+1
    }
    return(as.data.frame(eff))
}

0 votos

¿Podrías contarnos más sobre cómo obtuviste la frontera eficiente usando fPortfolio?

0 votos

@BobJansen, estoy utilizando la configuración predeterminada en fPortfolio, es decir, solo pasando los datos de rendimiento a él.

0 votos

Mi función objetivo es para la cartera óptima de media-varianza. La configuración fPortfolio que he establecido es para la cartera de varianza mínima, que es una simplificación de la función objetivo anterior.

2voto

halfdan Puntos 556

Ambos enfoques dan los mismos resultados para los pesos de las acciones pero resultados diferentes para los valores de lambda

El enfoque correcto es multiplicar la matriz de covarianza por 2 pero solo necesitas los pesos de las acciones así que es lo mismo

1voto

AK88 Puntos 1368

Los resultados que estás obteniendo del paquete fPortfolio son correctos. Y si no multiplicas tu matriz de covarianza por 2, obtendrás el mismo resultado del paquete quadprog. Por lo tanto, usa fPortfolio o quadprog sin el 2.

"1/2" en esa fórmula que mencionaste podría estar refiriéndose a algún problema específico. Sin embargo, también he visto este enfoque de multiplicar por 2 en estudios de optimización de carteras. Por ejemplo, Eric Zivot utilizó este método en sus materiales. No creo que sea correcto. Para estar seguro, te aconsejo que pases por un ejemplo sencillo utilizando Excel, completando manualmente todos los pasos requeridos.

EDICIÓN:

Investigué un poco más este problema e intenté el siguiente código:

library(fPortfolio)
library(quadprog)
ret = 100 * LPP2005.RET[,1:6]
Dmat1 <- cov(ret)     
Dmat2 = 2 * cov(ret)
Dmat3 = 10 * cov(ret)
n <- ncol(Dmat)      
dvec = rep(0, n)
Amat <- cbind(rep(1, n), diag(n))
bvec <- c(1, rep(0, n))
meq <- 1
## Dmat
## n
## dvec
## Amat
## bvec
qp.out1 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE)
qp.out2 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE)
qp.out3 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE)
qp.out1$solution
qp.out2$solution
qp.out3$solution

Obtuve los mismos pesos para todos los Dmats. Así que parece que en la obtención de pesos, multiplicar tu matriz de covarianza por una constante no cambia el resultado de la optimización. Sin embargo, cuando estás construyendo tu eff.frontier, todavía estás pasando esa matriz de covarianza multiplicada por n veces para obtener tus desviaciones estándar:

eff[iLoop,"StdDev"] <- sqrt(sum(sol$solution %*% colSums((Dmat * sol$solution))))

Creo que la solución es:

eff[iLoop,"StdDev"] <- sqrt(sum(sol$solution %*% colSums((cov(ret) * sol$solution))))

0 votos

Bueno, tu comentario es lo que pienso también, pero solo quiero encontrar una explicación adecuada.

0 votos

¿Explicación adecuada sobre por qué la fórmula tiene un término 1/2? ¿O sobre la corrección de los resultados?

0 votos

Mi pregunta de título: ¿por qué usar "cov" y no "cov x 2" como argumento?

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X