使用R中的本地搜索的Markowitz模型/投资组合优化

时间:2016-10-13 02:42:05

标签: r optimization lambda portfolio

我正在采取婴儿步骤使用元启发式来解决约束优化问题。我正在尝试使用R中的NMOF包解决基本的Markowitz均值 - 方差优化模型(如下所示)。

  Min 
   lambda * [sum{i=1 to N}sum{j = 1 to N}w_i*w_i*Sigma_ij] - (1-lambda) * [sum{i=1 to N}(w_i*mu_i)]
 subject to 
    sum{i=1 to N}{w_i} = 1
    0 <= w_i <= 1; i = 1,...,N

其中,lambda取0到1之间的值,N是资产数。

以下是我的代码(基于书:财务中的数值方法和优化):

    library(NMOF)

na <- dim(fundData)[2L]
ns <- dim(fundData)[1L]
Sigma <- cov(fundData)
winf <- 0.0
wsup <- 1.0
m <- colMeans(fundData)


resample <- function(x,...) x[sample.int(length(x),...)]


data <- list(R = t(fundData), 
             m = m,
             na = dim(fundData)[2L],
             ns = dim(fundData)[1L], 
             Sigma = Sigma, 
             eps = 0.5/100,
             winf = winf, 
             wsup = wsup,
             nFP = 100)

 w0 <- runif(data$na); w0 <- w0/sum(w0)

 OF <- function(w,data){    
   wmu <- crossprod(w,m)
   res <- crossprod(w, data$Sigma)
   res <- tcrossprod(w,res)
   result <- res - wmu
  }


 neighbour <- function(w, data){
   toSell <- w > data$winf
   toBuy <- w < data$wsup
   i <- resample(which(toSell), size = 1L)
   j <- resample(which(toBuy), size = 1L)
   eps <- runif(1) * data$eps
   eps <- min(w[i] - data$winf, data$wsup - w[j], eps)
   w[i] <- w[i] - eps
   w[j] <- w[j] + eps
   w
 }


 algo <- list(x0 = w0, neighbour = neighbour, nS = 5000L)
 system.time(sol1 <- LSopt(OF, algo, data))

我不确定如何在目标函数(OF)中包含lambda。上面的代码不包括OF中的lambda。我尝试使用for循环但导致以下错误:

OF <- function(w,data){

  lambdaSeq <- seq(.001,0.999, length = data$nFP)
  for(lambda in lambdaSeq){
  wmu <- crossprod(w,m)
  res <- crossprod(w, data$Sigma)
  res <- tcrossprod(w,res)
  result <- lambda*res - (1-lambda)*wmu 
  }
}

错误:

 Local Search.
    Initial solution:   
      |                                                                                          |   0%
    Error in if (xnF <= xcF) { : argument is of length zero
    Timing stopped at: 0.01 0 0.03

如果有人能在这方面帮助我,那就太好了。

P.S :我也知道这可以使用二次规划来解决。这只是一个包含其他约束的启动。

1 个答案:

答案 0 :(得分:1)

如果我理解正确,你想通过Local Search复制均值 - 方差有效前沿?然后,您需要为要包含在边界中的lambda的每个值运行本地搜索。

以下示例可帮助您继续前进。我首先附上包并设置列表data

require("NMOF")
data <- list(m = colMeans(fundData), ## expected returns
             Sigma = cov(fundData),  ## expected var of returns
             na = dim(fundData)[2L], ## number of assets
             eps = 0.2/100,          ## stepsize for LS
             winf = 0,               ## minimum weight
             wsup = 1,               ## maximum weight
             lambda = 1)

接下来,我计算最小方差情况的基准(即lambda等于1)。

## benchmark: the QP solution
## ==> this will only work with a recent version of NMOF,
## which you can get by saying:
##   install.packages('NMOF', type = 'source',
##                    repos = c('http://enricoschumann.net/R',
##                              getOption('repos')))
##
require("quadprog")
sol <- NMOF:::minvar(data$Sigma, 0, 1)

目标函数和邻域函数。我略微简化了这两个函数(为了清楚起见,在目标函数中使用crossprod可能会更有效。)

OF <- function(w, data){
    data$lambda * (w %*% data$Sigma %*% w) -
    (1 - data$lambda) * sum(w * data$m)
}

neighbour <- function(w, data){
    toSell <- which(w > data$winf)
    toBuy  <- which(w < data$wsup)
    i <- toSell[sample.int(length(toSell), size = 1L)]
    j <- toBuy[sample.int(length(toBuy), size = 1L)]
    eps <- runif(1) * data$eps
    eps <- min(w[i] - data$winf, data$wsup - w[j], eps)
    w[i] <- w[i] - eps
    w[j] <- w[j] + eps
    w
}

现在我们可以运行本地搜索了。由于它是一个相当大的数据集(200个资产), 您将需要相对大量的步骤来重现QP解决方案。

w0 <- runif(data$na) ## a random initial solution
w0 <- w0/sum(w0)
algo <- list(x0 = w0, neighbour = neighbour, nS = 50000L)
sol1 <- LSopt(OF, algo, data)

您可以将从本地搜索获得的权重与QP解决方案进行比较。

par(mfrow = c(3,1), mar = c(2,4,1,1), las = 1)
barplot(sol, main = "QP solution")
barplot(sol1$xbest, main = "LS solution")
barplot(sol - sol1$xbest,
        ylim = c(-0.001,0.001)) ## +/-0.1%

最后,如果您想计算整个边界,则需要针对data$lambda的不同级别重新运行此代码。