2015-06-03 87 views
0

我想在R的portfolioanalytics包中使用chart.EfficientFrontier函數來繪製我創建的有效邊界對象,但它保持失敗。基本上我試圖找到一個邊界,將最大限度地減少標準偏差。最終一旦我得到這個工作,我也想最大化年回報R投資組合分析圖表。有效的前沿函數

> 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 

現在我成功地創建了:

首先,我使用此代碼

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.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 

任何人都知道爲什麼會出現這種情況?當我使用摘要(prt.ef)時,我可以看到權重,但爲什麼chart.EfficientFrontier函數失敗?

+0

'chart.EfficientFrontier'希望能夠調用沒有權重的'pasd'來計算每個資產的sigma,並用權重來計算投資組合sigma。爲了消除錯誤信息,使用'pasd < - function(R,weights = NULL)as.numeric(StdDev(R = R,權重=權重)* sqrt(12))'使'pasd'像'StdDev'一樣工作。 。此外,爲了做一個一致的分​​析,你應該每年回報,但然後優化將計算每月和年度組合的相同權重。 – WaltS

+0

我改變了'pasd'函數,就像你的建議一樣,但chart.EfficientFrontier仍然給我錯誤。 (R = R,權重=權重):找不到對象'NuLL' StdDev中的錯誤(R = R,權重=權重) :找不到對象'NuLL' StdDev中的錯誤(R = R,權重=權重):找不到對象'NuLL' xlim [2] * 1.15錯誤:二進制運算符'非數字參數' – user3381431

回答

0

沒有找到錯誤的原因,但設置了它的部分工作限制!

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) 
+0

您能解釋一下限制是什麼?出於某種原因,我所看到的邊界是一條鋸齒狀的線條,而不是一條光滑的曲線。 – user3381431

0

行,所以我嘗試了pasd功能WaltS建議,以及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邊境地點已生成。 msg是什麼意思,爲什麼只產生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 
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

這種行爲必須規範,或者你正在使用的優化算法的影響。我從包quadprogsolve.QP做了相同的優化。這是結果。 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") 
+0

謝謝,我會嘗試的,但我不明白的是每月的回報乘以12來年化。我已經導入了一個月度回報系列,並且通過鏈接每個月回報(1 + r1)*(1 + r2)*(1 + r3).....(1 + r12) - 1 – user3381431

+0

您也可以使用'solve.QP'發佈優化代碼嗎? – user3381431

+0

我知道你需要每月EF數據的等效年化回報率和年度標準差,因爲你只需包含scale = 12。在這種情況下,你應該每個月投資一次。不同的歷史是每年都要改變問題進行投資,因爲您需要很長的一系列年度回報,在這種情況下,您可以複合每月回報。 – Robert

1

添加到羅伯特的意見,優化計算,每月的回報是一個二次規劃問題線性約束。當meanreturn客觀和StdDevvarrisk客觀,optimize.portfoliocreate.EfficientFrontier選擇ROI方法作爲利用solve.QP,對於這些種類的問題的有效解算器解算器。當risk目標更改爲pasd時,這些函數不會將其識別爲QP問題,因此使用DEoptim一般非線性問題求解器可能更適合解決非凸面問題而非凸面QP問題。見Differential Evolution with DEoptim。這似乎是鋸齒狀高效邊界的原因。

爲了有create.EfficientFrontier使用solve.QP,這是這種類型的問題更加有效和準確,你可以做一個自定義的矩函數計算的均值和方差,然後用參數momentFUN指定。然而,create.EfficientFrontier至少部分使用從回報直接計算的平均值,而不是從momentFUN使用mu。要處理這個問題,請將收益乘以12,並將差額除以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

在一天結束的時候它會更簡單,因爲羅伯特建議,使用月度收益來計算權重的有效邊界,然後用年度資產來計算投資回報率和標準差和標準差和兩種情況下的月重相同。但是,也許這個例子對於顯示自定義時刻和目標函數的使用很有用。

+0

感謝您的詳細解答。我剛剛開始使用R,並且花了我很多時間去做它的東西。現在我已經在excel中採取了這種做法,但回頭看看並試圖理解代碼是很好的。 – user3381431