为什么没有解决.QP和portfolio.optim产生相同的结果?

时间:2014-08-24 21:58:10

标签: r optimization portfolio quadprog

portfolio.optim {tseries}的文档说,solve.QP {quadprog}用于生成寻找最大化夏普比率的相切投资组合的解决方案。这意味着结果应与任何一种功能相同。我可能忽略了一些东西,但在这个简单的例子中,我得到了类似但不完全相同的解决方案,用于通过portfolio.optim和solve.QP来估计最优投资组合权重。结果不应该相同吗?如果是的话,我哪里错了?这是代码:

library(tseries)
library(quadprog)


# 1. Generate solution with solve.QP via: comisef.wikidot.com/tutorial:tangencyportfolio

# create artifical data
set.seed(1)
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
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))

# 2. Generate solution with portfolio.optim (using artificial data from above)
port.1 <-portfolio.optim(mData,riskless=rf)
port.1.w <-port.1$pw
port.1.w <-matrix(port.1.w)

# 3. Compare portfolio weights from the two methodologies:

compare <-cbind(w,port.1$pw)

compare

             [,1]        [,2]
 [1,]  0.337932967 0.181547633
 [2,]  0.073836572 0.055100415
 [3,]  0.160612441 0.095800361
 [4,]  0.164491490 0.102811562
 [5,]  0.005034532 0.003214622
 [6,]  0.147473396 0.088792283
 [7,] -0.122882875 0.000000000
 [8,]  0.127924865 0.067705050
 [9,]  0.026626940 0.012507530
[10,]  0.078949672 0.054834759

2 个答案:

答案 0 :(得分:3)

处理此类情况的唯一方法是浏览源代码。在您的情况下,可以通过tseries:::portfolio.optim.default访问它。

现在,为了找到这两个调用之间的区别,我们可以通过定义等效的辅助函数来缩小问题范围:

foo <- function(x, pm = mean(x), covmat = cov(x), riskless = FALSE, rf = 0) 
{
  x <- mData
  pm <- mean(x)
  covmat <- cov(x)
  k <- dim(x)[2]
  Dmat <- covmat
  dvec <- rep.int(0, k)
  a1 <- colMeans(x) - rf
  a2 <- matrix(0, k, k)
  diag(a2) <- 1
  b2 <- rep.int(0, k)
  Amat <- t(rbind(a1, a2))
  b0 <- c(pm - rf, b2)
  solve.QP(Dmat, dvec, Amat, bvec = b0, meq = 1)$sol
}

identical(portfolio.optim(mData, riskless=TRUE, rf=rf)$pw,
          foo(mData, riskless=TRUE, rf=rf))
#[1] TRUE

有了这个,你可以看到1)riskless=rf不是预期的方式,riskless=TRUE, rf=rf是正确的方式; 2)Amat和bvec有几个不同之处。

我不是投资组合优化的专家,所以我不知道这些额外限制背后的解释是什么,以及它们是否应该首先出现在那里,但至少你可以看到究竟是什么导致了这些差异

答案 1 :(得分:1)

由于tseries :: portfolio.optim()中的默认值“shorts = FALSE”,您的示例中出现了差异。因此,您必须更改参数或在solve.QP问题中添加非负性限制才能达到相同的结果。

编辑:虽然答案仍然适用,但似乎有一些其他奇怪的默认值与tseries :: portfolio.optim()。例如,它将最小回报要求设置为pm = mean(x),导致效率边界上的随机投资组合,而不是在没有回报要求时返回全局最小方差投资组合。结论:继续使用你的quadprog :: solve.QP解决方案。附上我使用的包装函数的一个例子(我刚开始使用R,虽然我很确定这可以提供数学上正确的结果,但它可能不是最干净的代码):

# --------------------------------------------------------------------------
#' Quadratic Optimization
#' @description Wrapper for quadratic optimization to calculate the general
#'              mean-variance portfolio.
#' @param S           [matrix] Covariance matrix.
#' @param mu          [numeric] Optional. Vector of expected returns.
#' @param wmin        [numeric] Optional. Min weight per asset.
#' @param wmax        [numeric] Optional. Max weight per asset.
#' @param mu_target   [numeric] Optional. Required return, if empty the optimization returns the global minimum variance portfolio
#' @return Returns the mean-variance portfolio or the global minimum variance portfolio
# --------------------------------------------------------------------------

meanvar.pf <- function(S,
                      mu=NULL,
                      wmin=-1000,
                      wmax=1000,
                      mu_target=NULL){
  if (!try(require(quadprog)))
    stop("Execute 'install.packages('quadprog')' and try again")
  if (missing(S))
    stop("Covariance matrix is missing")
  if (!is.null(mu) & dim(S)[1] != length(mu))
    stop("S and mu have non-conformable dimensions")
  N <- ncol(S)
  if (wmin >= 1/N)
    stop("wmin >= 1/N is not feasible")
  if (wmax <= 1/N)
    stop("wmax <= 1/N is not feasible")    
  meq <- 1
  bvec <- c(1, rep(wmin,N), -rep(wmax,N))
  Amat <- cbind(rep(1, N), diag(N), -diag(N))
  if (!is.null(mu_target)) {
    if (is.null(mu))
      stop("Vector of asset returns is missing")
    Amat <- cbind(mu, Amat)
    bvec <- c(mu_target, bvec)
    meq <- 2
  }
  result <- quadprog::solve.QP(Dmat=S, 
                              dvec=rep(0, N), 
                              Amat=Amat, 
                              bvec=bvec, 
                              meq=meq)
  return(result)
}