R 中的顺序二次规划以找到等权重风险贡献组合的最佳权重

Sequential Quadratic Programming in R to find optimal weights of an Equally-Weighted Risk Contribution Portfolio

问题介绍

我正在尝试在 R 中写下一段代码,以获得等权重贡献 (ERC) 投资组合的权重。正如你们中的一些人所知,投资组合构建是由 Maillard, Roncalli and Teiletche.

提出的

跳过技术细节,为了找到 ERC 投资组合的最佳权重,需要解决以下顺序二次规划问题:

与:

假设我们正在分析 N 项资产。在上面的公式中,我们有 x 是投资组合权重的 (N x 1) 向量,Σ 是资产 returns 的 (N x N) 方差-协方差矩阵.

到目前为止我做了什么

使用解决SQP问题的函数slsqp of the package nloptr,我想解决上面的最小化问题。这是我的代码。首先,要最小化的objective函数:

ObjFuncERC <- function (x, Sigma) {
sum <- 0
R <- Sigma %*% x
    for (i in 1:N) {
        for (j in 1:N) {
            sum <- sum + (x[i]*R[i] - x[j]*R[j])^2
        }
    }
}

其次,起点(我们从一个等权重的投资组合开始):

x0 <- matrix(1/N, nrow = N, ncol = 1)

然后,等式约束(权重之和必须为一,即:权重之和减一等于零):

heqERC <- function (x) {
    h <- numeric(1)
    h[1] <- (t(matrix(1, nrow = N, ncol = 1)) %*% x) - 1
    return(h)
}

最后,下限和上限约束(权重不能超过1且不能小于0):

lowerERC <- matrix(0, nrow = N, ncol = 1)
upperERC <- matrix(1, nrow = N, ncol = 1)

所以应该输出最佳权重的函数是:

slsqp(x0 = x0, fn = ObjFuncERC, Sigma = Sigma, lower = lowerERC, upper = upperERC, heq = heqERC)

不幸的是,我不知道如何与您分享我的方差-协方差矩阵(其名称为 Sigma 并且是一个 (29 x 29) 矩阵,因此 N = 29)以便重现我的结果,您仍然可以模拟一个

输出错误

运行 上面的代码会产生以下错误:

Error in nl.grad(x, fn) : 
Function 'f' must be a univariate function of 2 variables.

伙计们,我不知道该怎么办。可能我误解了必须如何写下来才能让函数 slsqp 理解要做什么。 有人可以帮助我了解如何解决问题并获得我想要的结果吗?


UPDATE ONE:正如@jogo 在评论中指出的那样,我已经更新了代码,但它仍然会产生错误。上面的代码和错误现已更新。


更新 2:根据@jaySf 的要求,这是允许您重现我的错误的完整代码。

## ERC Portfolio Test
# Preliminary Operations
rm(list=ls())
require(quantmod)
require(nloptr)

# Load Stock Data in R through Yahoo! Finance
stockData <- new.env()
start <- as.Date('2014-12-31')
end <- as.Date('2017-12-31')
tickers <-c('AAPL','AXP','BA','CAT','CSCO','CVX','DIS','GE','GS','HD','IBM','INTC','JNJ','JPM','KO','MCD','MMM','MRK','MSFT','NKE','PFE','PG','TRV','UNH','UTX','V','VZ','WMT','XOM')
getSymbols.yahoo(tickers, env = stockData, from = start, to = end, periodicity = 'monthly')

# Create a matrix containing the price of all assets
prices <- do.call(cbind,eapply(stockData, Op))
prices <- prices[-1, order(colnames(prices))]
colnames(prices) <- tickers

# Compute Returns
returns <- diff(prices)/lag(prices)[-1,]

# Compute variance-covariance matrix 
Sigma <- var(returns)
N <- 29

# Set up the minimization problem
ObjFuncERC <- function (x, Sigma) {
sum <- 0
R <- Sigma %*% x
    for (i in 1:N) {
        for (j in 1:N) {
            sum <- sum + (x[i]*R[i] - x[j]*R[j])^2
        }
    }
}


x0 <- matrix(1/N, nrow = N, ncol = 1)


heqERC <- function (x) {
    h <- numeric(1)
    h[1] <- t(matrix(1, nrow = N, ncol = 1)) %*% x - 1
}

lowerERC <- matrix(0, nrow = N, ncol = 1)
upperERC <- matrix(1, nrow = N, ncol = 1)

slsqp(x0 = x0, fn = ObjFuncERC, Sigma = Sigma, lower = lowerERC, upper = upperERC, heq = heqERC)

我在您的代码中发现了几个错误。例如,ObjFuncERC 没有 returning 任何值。您应该改用以下内容:

# Set up the minimization problem
ObjFuncERC <- function (x, Sigma) {
  sum <- 0
  R <- Sigma %*% x
  for (i in 1:N) {
    for (j in 1:N) {
      sum <- sum + (x[i]*R[i] - x[j]*R[j])^2
    }
  }
  sum
}

heqERC也没有return什么,我也稍微改变了你的功能

heqERC <- function (x) {
    sum(x) - 1
}

我进行了这些更改并尝试了 slsqp 而不使用 lowerupper,并且成功了。不过,要考虑的另一件事是将 lowerERCupperERC 设置为矩阵。请改用以下内容:

lowerERC <- rep(0,N)
upperERC <- rep(1,N) 

希望对您有所帮助。