【问题标题】:R portfolio analytics chart.EfficientFrontier functionR 投资组合分析图表。EfficientFrontier 函数
【发布时间】:2015-06-03 08:15:31
【问题描述】:

我正在尝试使用 R 中的投资组合分析包中的 chart.EfficientFrontier 函数来绘制我创建的有效边界对象,但它一直失败。基本上,我试图找到一个可以最小化 annaulized 标准偏差的边界。最终,一旦我完成这项工作,我还希望最大化年化回报。

首先我使用这段代码创建了一个年化标准差函数

pasd <- function(R, weights){
  as.numeric(StdDev(R=R, weights=weights)*sqrt(12)) # hardcoded for monthly data
  # as.numeric(StdDev(R=R, weights=weights)*sqrt(4)) # hardcoded for quarterly data
}

我导入了一个包含每月回报的 csv 文件,我的投资组合对象如下所示:

> prt
**************************************************
PortfolioAnalytics Portfolio Specification 
**************************************************

Call:
portfolio.spec(assets = colnames(returns))

Number of assets: 3 
Asset Names
[1] "Global REITs"      "Au REITs"          "Au Util and Infra"

Constraints
Enabled constraint types
        - leverage 
        - long_only 

Objectives:
Enabled objective names
        - mean 
        - pasd 

现在我使用这条线成功地创建了一个高效的边界对象:

prt.ef <- create.EfficientFrontier(R = returns, portfolio = prt, type = "DEoptim", match.col = "pasd")

但是当我尝试绘制它时,我收到以下错误消息。

> chart.EfficientFrontier(prt.ef, match.col="pasd")
Error in StdDev(R = R, weights = weights) : 
  argument "weights" is missing, with no default
In addition: There were 26 warnings (use warnings() to see them)
Error in StdDev(R = R, weights = weights) : 
  argument "weights" is missing, with no default
Error in StdDev(R = R, weights = weights) : 
  argument "weights" is missing, with no default
Error in xlim[2] * 1.15 : non-numeric argument to binary operator

有人知道为什么会这样吗?当我使用 summary(prt.ef) 时,我可以看到权重,但为什么 chart.EfficientFrontier 函数失败了?

【问题讨论】:

  • chart.EfficientFrontier 期望能够在没有权重的情况下调用pasd 来计算每个资产的 sigma,并使用权重来计算投资组合的 sigma。要消除错误消息,请使用 pasd &lt;- function(R, weights=NULL) as.numeric(StdDev(R=R, weights=weights)*sqrt(12)) 使 pasdStdDev 一样工作。此外,为了进行一致的分析,您应该将回报年化,然后优化将为月度和年化投资组合计算相同的权重。
  • 我按照您的建议更改了 pasd 函数,但 chart.EfficientFrontier 仍然给我错误。 chart.EfficientFrontier(prt.ef, match.col="pasd") Error in StdDev(R = R, weights = weights) : object 'NuLL' not found Error in StdDev(R = R, weights = weights) : object 'NuLL' not found Error in StdDev(R = R, weights = weights) : object 'NuLL' not found Error in xlim[2] * 1.15 : non-numeric argument to binary operator

标签: r mathematical-optimization portfolio


【解决方案1】:

正如@WaltS 所建议的,您需要始终如一地执行函数来实现年均值和风险回报。

但实际上,要获得年度统计数据,您有两种选择,您没有使用任何一种:

1) 以月度数据进行优化,采用规范中原有的风险回报函数。对于绘图,您可以进行分析

Port.Anua.Returns=prt.ef$frontier[,1]*12 
Port.Anua.StDev=prt.ef$frontier[,2]*12^.5

月度或年化投资组合的权重相同。

prt.ef$frontier[,-(1:3)]

2) 将您的月化收益乘以 12 转换为年化收益。然后按照通常的程序进行优化,所有风险和收益都将在 prt.ef$frontier 中进行年化。

与 EF 中的锯齿线有关。使用您的投资组合规范,我还能够重新创建相同的行为。对于以下情节,我使用了edhec 数据,您的规范与原始meanStdDev 在目标中:

data(edhec)
returns <- edhec[,1:3]

该行为必须受到规范或您使用的优化算法的影响。我对包quadprog 中的solve.QP 做了同样的优化。这就是结果。

更新

代码在这里:

require(quadprog) 
#min_x(-d^T x + 1/2 b^T D x) r.t A.x>=b
MV_QP<-function(nx, tarRet, Sig=NULL,long_only=FALSE){
  if (is.null(Sig)) Sig=cov(nx)
  dvec=rep(0,ncol(Sig))
  meq=2
  Amat=rbind(rep(1,ncol(Sig)),
             apply(nx,2,mean) )
  bvec=c(1,tarRet )
  if (long_only) {
    meq=1
    Amat=Amat[-1,]
    Amat=rbind(Amat,
               diag(1,ncol(Sig)),
               rep(1,ncol(Sig)),
               rep(-1,ncol(Sig)))
    bvec=bvec[-1]
    bvec=c(bvec,
               rep(0,ncol(Sig)),.98,-1.02)
  }
  sol  <- solve.QP(Dmat=Sig, dvec, t(Amat), bvec, meq=meq)$solution 
}

steps=50
x=returns
 µ.b <- apply(X = x, 2, FUN = mean) 
long_only=TRUE
range.bl <- seq(from = min(µ.b), to = max(µ.b)*ifelse(long_only,1,1.6), length.out = steps) 
risk.bl <- t(sapply(range.bl, function(targetReturn) { 
  w <- MV_QP(x, targetReturn,long_only=long_only) 
  c(sd(x %*% w),w)  }))

weigthsl=round(risk.bl[,-1],4)
colnames(weigthsl)=colnames(x)
weigthsl
risk.bl=risk.bl[,1]
rets.bl= weigthsl%*%µ.b
fan=12
plot(x = risk.bl*fan^.5, y = rets.bl*fan,col=2,pch=21,
     xlab = "Annualized Risk ", 
     ylab = "Annualized Return", main = "long only EF with solve.QP")

【讨论】:

  • 谢谢,我会尝试,但我不明白的是通过将每月回报乘以 12 来年化每月回报。我已经在导入每月回报系列,我将在那里获得年化回报链接每个月的回报 (1+r1)*(1+r2)*(1+r3).....(1+r12) - 1
  • 另外,您能否使用solve.QP发布优化代码?
  • 我知道您想要与每月 EF 数据等效的年化回报和年度标准差,因为您只需包含 scale=12。在这种情况下,您应该每个月进行投资。不同的历史是将问题转化为每年进行投资,因为您将需要一长串年度回报,在这种情况下,您可以复合每月回报。
【解决方案2】:

除了 Robert 的 cmets,每月收益的优化计算是一个具有线性约束的二次规划问题。当meanreturn 目标并且StdDevvarrisk 目标时,optimize.portfoliocreate.EfficientFrontier 选择ROI 方法作为求解器,它使用solve.QP,一个高效的求解器对于这类问题。当risk 目标更改为pasd 时,这些函数不会将其识别为QP 问题,因此使用DEoptim 一个通用非线性问题求解器可能更适合解决非凸QP 问题而不是凸QP 问题。见Differential Evolution with DEoptim。这似乎是锯齿状有效边界的原因。

为了让create.EfficientFrontier 使用solve.QP,这对于此类问题更加有效和准确,您可以创建一个自定义矩函数来计算均值和方差,然后使用参数@987654337 指定它@。然而,create.EfficientFrontier 至少部分使用了直接从返回值计算的平均值,而不是使用来自momentFUNmu。为了解决这个问题,将收益相乘并将方差除以 12,如下例所示。

library(PortfolioAnalytics)
  data(edhec)
  returns <- edhec[,1:3]
#  define moment function
  annualized.moments <- function(R, scale=12, portfolio=NULL){
    out <- list()
    out$mu <-    matrix(colMeans(R), ncol=1)
    out$sigma <- cov(R)/scale
    return(out)
  }
# define portfolio
  prt <- portfolio.spec(assets=colnames(returns))
  prt <- add.constraint(portfolio=prt, type="long_only")
  #  leverage defaults to weight_sum = 1 so is equivalent to full_investment constraint
  prt <- add.constraint(portfolio=prt, type="leverage")
  prt <- add.objective(portfolio=prt, type="risk", name="StdDev")
# calculate and plot efficient frontier
  prt_ef <- create.EfficientFrontier(R=12*returns, portfolio=prt, type="mean-StdDev", 
                                      match.col = "StdDev", momentFUN="annualized.moments", scale=12)
  xlim <- range(prt_ef$frontier[,2])*c(1, 1.5)
  ylim <- range(prt_ef$frontier[,1])*c(.80, 1.05)
  chart.EfficientFrontier(prt_ef, match.col="StdDev", chart.assets = FALSE, 
                          labels.assets = FALSE, xlim=xlim, ylim=ylim )
  points(with(annualized.moments(12*returns, scale=12), cbind(sqrt(diag(sigma)), mu)), pch=19 ) 
  text(with(annualized.moments(12*returns, scale=12), cbind(sqrt(diag(sigma)), mu)), 
       labels=colnames(returns), cex=.8, pos=4) 
  chart.EF.Weights(prt_ef, match.col="StdDev")

资产的均值和标准差也需要调整,因此绘制在chart.EfficientFrontier之外,如下图所示。

最终,正如罗伯特所建议的那样,使用每月回报计算有效前沿的权重,然后使用年化资产均值和标准差以及每月权重计算投资组合回报和标准差会更简单在这两种情况下都是相同的。然而,也许这个例子对于展示自定义矩和目标函数的使用很有用。

【讨论】:

  • 感谢您的详细回答。我才刚刚开始使用 R,而且我花了很长时间才能在其中做一些事情。目前我已经在 excel 中进行了此操作,但最好回顾一下并尝试理解代码。
【解决方案3】:

没有找到错误的原因,但是设置了部分的限制!

prt.ef$frontier  #see the EF
xylims=apply(prt.ef$frontier[,c(2,1)],2,range)*c(.98,1.01)
chart.EfficientFrontier(prt.ef, match.col="pasd", 
      main="Portfolio Optimization", 
      xlim=xylims[,1], ylim=xylims[,2])
#or
plot(prt.ef$frontier[,c(2,1)],col=2)

【讨论】:

  • 您能解释一下限制的作用吗?出于某种原因,我看到的边界是锯齿状的线,而不是平滑的曲线。
【解决方案4】:

好的,所以我尝试了 WaltS 建议的 pasd 函数,chart.EfficientFrontier 似乎有效,但它给了我一条锯齿线而不是一条平滑线。

我现在使用以下代码创建了年化回报函数:

pamean <- function(R, weights=NULL){Return.annualized(apply(as.xts(t(t(R) * weights)),1,sum))}

并将其作为目标添加到我的投资组合 prt 中。

> prt
**************************************************
PortfolioAnalytics Portfolio Specification 
**************************************************

Call:
portfolio.spec(assets = colnames(returns))

Number of assets: 3 
Asset Names
[1] "Global REITs"      "Au REITs"          "Au Util and Infra"

Constraints
Enabled constraint types
        - long_only 
        - leverage 

Objectives:
Enabled objective names
        - pamean 
        - pasd 

然后我使用这条线再次创建有效边界:

> prt.ef <- create.EfficientFrontier(R=returns, portfolio=prt, type="DEoptim", match.col="pasd")

但是当我使用汇总函数时,我看到只生成了 1 个边界点。错误消息是什么意思,为什么只产生 1 分?

> summary(prt.ef)
**************************************************
PortfolioAnalytics Efficient Frontier 
**************************************************

Call:
create.EfficientFrontier(R = returns, portfolio = prt, type = "DEoptim", 
    match.col = "pasd")

Efficient Frontier Points: 1 

Error in `colnames<-`(`*tmp*`, value = character(0)) : 
  attempt to set 'colnames' on an object with less than two dimensions

【讨论】:

    猜你喜欢
    • 2022-11-18
    • 2021-01-20
    • 2021-12-18
    • 1970-01-01
    • 1970-01-01
    • 2021-04-22
    • 2021-01-16
    • 2016-07-07
    • 1970-01-01
    相关资源
    最近更新 更多