我正在尝试使用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函数失败?
答案 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
数据,您的规范包含了目标中的原始mean
和StdDev
:
data(edhec)
returns <- edhec[,1:3]
该行为必须受您使用的规范或优化算法的影响。我使用包solve.QP
中的quadprog
进行了相同的优化。这是结果。
更新
代码在这里:
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)
添加罗伯特的评论,带月回报的优化计算是线性约束的二次规划问题。如果mean
是return
目标且StdDev
或var
是risk
目标,则optimize.portfolio
和create.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
之外绘制并显示在下面的图表中。
在一天结束时,正如罗伯特建议的那样,使用月度回报计算有效边界的权重,然后使用年化资产平均值和标准差以及月度权重计算投资组合收益和标准差,这将更简单这两种情况都是一样的。但是,也许这个例子对于显示自定义矩和目标函数的使用很有用。
答案 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