solve.QP R 函式中的 Dmat 參數:Cov 還是 2*Cov?
背景
我的最終目標是從股票指數(例如 S&P500)的 100 隻股票中找到位於有效前沿的投資組合。
這種有效的投資組合將使其變異數與股票指數變異數相同。總結一下,最大化給定目標風險的回報。
問題
我首先學習瞭如何使用 PortfolioAnalytics 包,但是每當我將參數type=“mean-StdDev " 傳遞給函式時,函式 create.efficientFrontier 都會出錯。
在沒有解決上述問題的情況下,我決定使用 fPortfolio 包。我有一個有效的邊界,但我無法得到一個包含權重、收益和變異數的矩陣,所以我可以對變異數列進行二進制搜尋,然後選擇相應的權重(也許有一種方法,但我是新手R)。
如果沒有解決上述問題,我決定直接使用solve.QP 解決方案。我終於能夠做我想做的事情。
一旦我得到一個有效的邊界,我決定將它與我從 fPortfolio 得到的進行比較。令我驚訝的是,當收益相同時,變異數結果顯著不同。一旦我排除故障,我發現差異是由於 Dmat 參數,即共變異數矩陣。
我將Dmat <- Cov * 2傳遞給solve.QP 函式,但如果我改為使用Dmat <- Cov,那麼我會從 fPortfolio 獲得相同的結果。沒有任何改變,相同的數據集,相同的約束。顯然,solve.QP 的投資組合變異數是 fPortfolio 的變異數的兩倍。
我在 fPortfolio 中使用最基本的預設配置,即只將返回數據集傳遞給它。
MV Portfolio Frontier Estimator: covEstimator Solver: solveRquadprog Optimize: minRisk Constraints: LongOnly
問題
我在網路上遇到了一些程式碼,將共變異數矩陣乘以 2並將其作為Dmat傳遞。然而,其他一些程式碼只是將共變異數矩陣作為 Dmat 傳遞給 solve.QP 函式(即,不將其乘以 2)。
- 哪種方法是正確的?
根據我對二次規劃和 solve.QP 函式的研究,我相信共變異數矩陣必須乘以 2。
solve.QP 常式實現了 Goldfarb 和 Idnani (1982, 1983) 的對偶方法,用於求解形式為 min(-d^T b + 1/2 b^TD b) 且約束為 A^T b > 的二次規劃問題= b_0。
均值變異數優化(有效邊界)是形式為 min(w^TD w - q R^T w) 的二次規劃問題,約束條件為 A^T w >= w_0。
因此,在將 MV 目標函式轉換為 solve.QP 使用的等效形式時,共變異數矩陣必須乘以 2。
但是,這意味著fPortfolio 中的程式碼不正確。
- 以前有人注意到 fPortfolio 的這種行為嗎?
我想我在這裡遺漏了一些非常基本的東西!
程式碼
eff.frontier <- function (ret, max.allocation=NULL, rf=0, risk.limit=.5, risk.increment=.005) { Dmat <- 2 * cov(ret) n <- ncol(Dmat) Amat <- cbind(1, diag(n)) bvec <- c(1, rep(0, n)) meq <- 1 if(!is.null(max.allocation)){ Amat <- cbind(Amat, -diag(n)) bvec <- c(bvec, rep(-max.allocation, n)) } nLoops <- risk.limit / risk.increment + 1 iLoop <- 1 eff <- matrix(.0, nrow=nLoops, ncol=n+3) colnames(eff) <- c(colnames(returns), "Return", "StdDev", "SharpeRatio") for (i in seq(from=0, to=risk.limit, by=risk.increment)) { dvec <- colMeans(ret) * i sol <- solve.QP(Dmat=Dmat, dvec=dvec, Amat=Amat, bvec=bvec, meq=meq) eff[iLoop,"StdDev"] <- sqrt(sum(sol$solution %*% colSums((Dmat * sol$solution)))) eff[iLoop,"Return"] <- as.numeric(sol$solution %*% colMeans(ret)) eff[iLoop,"SharpeRatio"] <- (eff[iLoop,"Return"]-rf) / eff[iLoop,"StdDev"] eff[iLoop,1:n] <- sol$solution iLoop <- iLoop+1 } return(as.data.frame(eff)) }
您從fPortfolio包中獲得的結果是正確的。如果您不將共變異數矩陣乘以 2,您將從quadprog包中得到相同的結果。所以,要麼使用fPortfolio要麼使用quadprog而不使用 2。
您找到的那個公式中的“1/2”可能指的是一些特定的問題。但是,我在投資組合優化研究中也看到了這種乘以 2 的方法。例如,Eric Zivot 在他的材料中使用了這種方法。我不認為這是正確的。可以肯定的是,我建議您使用 Excel 完成一個簡單的範例,手動完成所需的所有步驟。
編輯:
進一步研究了這個問題並嘗試了以下程式碼:
library(fPortfolio) library(quadprog) ret = 100 * LPP2005.RET[,1:6] Dmat1 <- cov(ret) Dmat2 = 2 * cov(ret) Dmat3 = 10 * cov(ret) n <- ncol(Dmat) dvec = rep(0, n) Amat <- cbind(rep(1, n), diag(n)) bvec <- c(1, rep(0, n)) meq <- 1 ## Dmat ## n ## dvec ## Amat ## bvec qp.out1 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE) qp.out2 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE) qp.out3 = solve.QP(Dmat, dvec, Amat, bvec, meq, FALSE) qp.out1$solution qp.out2$solution qp.out3$solution
我得到了相同的重量
Dmats
。因此,看起來將共變異數矩陣乘以常數的權重不會改變優化結果。但是,當您建構您的時,eff.frontier
您仍然通過那些 n 倍的共變異數矩陣來獲得您的標準偏差:eff[iLoop,"StdDev"] <- sqrt(sum(sol$solution %*% colSums((Dmat * sol$solution))))
我認為解決方案是:
eff[iLoop,"StdDev"] <- sqrt(sum(sol$solution %*% colSums((cov(ret) * sol$solution))))