R组合分析图表.EfficientFrontier函数

时间:2015-06-03 08:15:32

标签: r mathematical-optimization portfolio

我正在尝试使用R中的portfolioanalytics包中的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函数失败?

4 个答案:

答案 0 :(得分:2)

正如@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]

enter image description here

该行为必须受您使用的规范或优化算法的影响。我使用包solve.QP中的quadprog进行了相同的优化。这是结果。 enter image description here

更新

代码在这里:

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")

答案 1 :(得分:1)

添加罗伯特的评论,带月回报的优化计算是线性约束的二次规划问题。如果meanreturn目标且StdDevvarrisk目标,则optimize.portfoliocreate.EfficientFrontier选择{ROI 1}}方法作为求解器使用solve.QP,这是一种有效解决这些问题的方法。当risk目标更改为pasd时,这些功能不会将此识别为QP问题,因此使用DEoptim一般非线性问题求解器可能更适合解决非凸问题而非比凸QP的。见Differential Evolution with DEoptim。这似乎是锯齿状有效前沿的原因。

为了create.EfficientFrontier使用solve.QP,这对于此类问题更有效和准确,您可以创建自定义时刻函数来计算均值和方差,然后使用论证momentFUN。但是,create.EfficientFrontier至少部分使用直接从退货计算的方法,而不是使用mu中的momentFUN。要处理这个问题,请将回报乘以并将方差除以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之外绘制并显示在下面的图表中。

enter image description here

在一天结束时,正如罗伯特建议的那样,使用月度回报计算有效边界的权重,然后使用年化资产平均值和标准差以及月度权重计算投资组合收益和标准差,这将更简单这两种情况都是一样的。但是,也许这个例子对于显示自定义矩和目标函数的使用很有用。

答案 2 :(得分:0)

找不到错误的原因,但设置限制部分有效!

<div class="row btn btn-default btn-block" onclick="active_class('B105')">
                <div class="col-xs-4" style="width: 230px">History(Ε)</div>
                <div class="col-xs-2" style="width: 70px" >13:00:00</div>
                <div class="col-xs-2" style="width: 70px" >15:00:00</div>
                <div class="col-xs-2" style="width: 70px" >B105</div>
 </div>

答案 3 :(得分:0)

好吧所以我尝试了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