股票

無法通過在 R 中模擬許多隨機投資組合來複製最小變異數投資組合變異數

  • February 18, 2021

我使用道瓊斯指數中的 30 隻股票計算了理論最小變異數投資組合。使用的公式是:

$$ \underset{N\times 1}{\omega_{mvp}}=\frac{\lambda}{2}\cdot \Sigma^{-1}\iota=\frac{\Sigma^{-1}\iota}{\iota’\Sigma^{-1}\iota} $$

在哪裡 $ \iota $ 是一個 $ N\times 1 $ 包含 1 的向量。

對於下載的數據,我得到大約 0.0002712748,我在腳本中將其稱為 Sigma_mvp。

然後我為資產生成一百萬個不同的向量,每個向量包含 30 個權重。權重可以是負數,我通過除以列總和來確保它們總和為一。

我的問題是:我設法用這些隨機權重得到的最小變異數是 0.0004467729,所以一定有問題。

有任何想法嗎?希望問題很清楚。

我的程式碼提供如下:

library(tidyquant)
library(tidyverse)

############ Getting Data for DOW ##############

tickers <- tq_index("DOW")

N <- length(tickers$symbol) # number of assets = 30

ones <- as.matrix(rep(1,N), ncol = 1) # one vector for later use

data <- tickers %>% tq_get(get = "stock.prices")

# calculate weekly returns

returns <- data %>% 
   group_by(symbol) %>% 
   tq_transmute(select = adjusted,
                mutate_fun = to.weekly,
                indexAt = "lastof") %>% 
   mutate(return = (log(adjusted) - log(lag(adjusted)))) %>% 
   na.omit()

# mean return vector

asset_returns <- returns %>% group_by(symbol) %>% 
 summarise(expected_return = mean(return)) %>% 
 select(expected_return) %>% as.matrix()

rownames(asset_returns) <- tickers$symbol %>% sort()

# create covariance matrix

Sigma <- returns %>%
 select(-adjusted) %>%
 pivot_wider(names_from = symbol, values_from = return) %>% # reorder data to a T x N matrix
  na.omit() %>% # remove NA that got generated by "DOW"
 select(-date) %>%
 cov(use = "pairwise.complete.obs")

Sigma <- Sigma[rownames(asset_returns),rownames(asset_returns)] # reorder matrix to match asset_return vector sequence

############## Generating random portfolios ###################

# random weights

w_rdm <- matrix(runif(n = 1000000 * N, min = -3, max = 3), nrow = N)

w_rdm <- apply(w_rdm,2,function(x){x/sum(x)})

# Create points

eff_frontier_rdm <- matrix(0, nrow = 1000000, ncol = 2)

for(i in 1:ncol(w_rdm)){
 
 eff_frontier_rdm[i,1] <- t(w_rdm[,i, drop = F]) %*% asset_returns
 
 eff_frontier_rdm[i,2] <- t(w_rdm[,i, drop = F]) %*% Sigma %*% w_rdm[,i, drop = F]
 
}

colnames(eff_frontier_rdm) <- c("return", "variance")

eff_frontier_rdm <- eff_frontier_rdm %>% as_tibble()

# smallest variance achieved with random portoflios

min(eff_frontier_rdm$variance)

# Computing the minimum variance portfolio

lambda <- 2 / as.numeric((t(ones) %*% solve(Sigma) %*% ones))

w_mvp <- (solve(Sigma) %*% ones) * lambda/2

Sigma_mvp <- t(w_mvp) %*% Sigma %*% w_mvp

# theoretical min variance portoflio

Sigma_mvp

我使用下面的程式碼添加了模擬投資組合的圖片,具有理論上正確的有效邊界。

在此處輸入圖像描述

根據答案,我設法創建了以下內容

感謝不同的建議。根據以上答案,我通過以下過程解決了我的問題:

給定一些共變異數矩陣 Σ 和一個預期的返迴向量,我稱之為asset_returns,我使用了以下步驟:

使用兩個共同基金定理從位於前沿的投資組合中選擇一些隨機權重矩陣。通過從標準法線繪製,為每個權重添加一些雜訊。通過除以和來正規化創建的向量。使用創建的權重向量計算投資組合變異數和預期收益。在創建了 100 萬個這樣的隨機權重後,我設法填充了邊界內的區域。創建更多的點將填滿它。

該解決方案基於我在文章中得到的答案。

eff_frontier_rdm <- matrix(0, nrow = 1000000, ncol = 2)

for(i in 1:nrow(eff_frontier_rdm)){
 
 c <- runif(1, min = -4, max = 4) # draw random number
 
 w = c * w_mvp + (1-c) * port_2$w_eff # create weight
 
 eps <- matrix(rnorm(N, mean = 0, sd = 0.1), ncol = 1)
 
 w = w + eps
 
 w = w / sum(w)
 
 eff_frontier_rdm[i,1] <- t(w) %*% asset_returns
 
 eff_frontier_rdm[i,2] <- t(w) %*% Sigma %*% w
 
}

在此處輸入圖像描述

我想我理解你的問題。您的權重不會均勻分佈在所需的空間上。相反,您的權重被捆綁在一起,極端權重(接近 1 的權重)比應有的要少。

例如,讓我們考慮第一個權重(或任何其他權重)應該在 0.8 和 1.0 之間的頻率。由於區間的長度

$$ 0.8,1.0 $$是區間的十分之一$$ -1.0,1.0 $$,百分之十的生成向量的第一權重應該在 0.8 和 1.0 之間。(同意?)。如果您測試隨機生成的向量,我想您會發現遠少於 10% 的第一個權重在此範圍內(可能根本沒有)。 你可能會問,這怎麼可能呢,因為第一步你在 -1 和 1 之間隨機生成權重。問題出現在第二步,你除以權重的總和。正如日本諺語所說:“釘子越長,釘得越多”。如果一個(或多個)隨機權重接近 1,則權重之和將很大,除法將相應地“錘擊”大權重。結果:很少有大重量。但不要相信我的直覺,檢查你生成的數據。

解決辦法是什麼?您如何統一生成投資組合權重?舒曼先生連結的 Patrick Burns 網站可能會有所幫助。就我個人而言,我在必須生成 0 到 1 之間的權重的上下文中發現了這個問題。我發現這個 CS StackExchange 問題很有幫助https://cs.stackexchange.com/questions/3227/uniform-sampling-from-a-simplex我什至在Random Portfolios vs Efficient Frontier中寫了一個算法(我認為這個連結中的圖片對你來說很熟悉,靠近邊界的點太少了)。你的問題有點不同,因為你允許空頭頭寸,所以你的權重必須在 -1 到 +1 之間。必須相應地修改算法。

我對此的想法是,由於多頭/空頭投資組合由多頭投資組合和空頭投資組合組成,您可以分別生成正權重和負權重。但我還沒有最終確定這將如何工作。我希望我的上述言論有所幫助。

引用自:https://quant.stackexchange.com/questions/61222