R PortfolioAnalytics create.EfficientFrontier () путаница с ожидаемыми доходами - PullRequest
0 голосов
/ 24 апреля 2020

ФОН: Интересно, можете ли вы мне помочь. Я знаком с оптимизацией портфеля. Я не эксперт, но я обычно строю свои собственные оптимизаторы для создания эффективных границ, основанных на четырехпрограммных или численных методах. Я только начинаю использовать PortfolioAnalytics, так как он выглядит действительно хорошо, и меня интересуют различные доступные решатели.

ЦЕЛЬ: Я хочу вычислить второй момент возврата активов (и выше) используя набор исторических возвратов, но чтобы указать первый момент (т.е. использовать мои собственные ожидаемые результаты). Я указал ожидаемые возвраты, как указано в документации и виньетках пакета.

ВЫПУСК: Я не понимаю, что делает create.EfficientFrontier (). Я вкладываю свои ожидаемые доходы, и эффективная граница не меняется. Чтобы проверить, что происходит, (i) я поставил гораздо более высокую ожидаемую доходность в качестве теста, и граница не поднимается; но (ii) входные данные что-то делают, потому что, если я обнуляю актив с наивысшей доходностью, граница сжимается; и (iii) если я переверну порядок ожидаемой доходности, чтобы более волатильные активы имели более низкую ожидаемую доходность, граница изменится.

ВОПРОС: Я был бы очень признателен, если бы кто-нибудь мог сказать мне как сделать границу, используя мои собственные ожидаемые доходы, а не исторические возвращения по умолчанию.

Большое спасибо, действительно,

Джон

Воспроизводимый пример


R version 3.6.1 (2019-07-05) -- "Action of the Toes"
Copyright (C) 2019 The R Foundation for Statistical Computing
Platform: x86_64-w64-mingw32/x64 (64-bit)

#Load packages

library(quadprog)
library(lubridate)
library(PortfolioAnalytics)
library(ROI)
library(ROI.plugin.glpk)
library(ROI.plugin.quadprog)

#Create some fake data (no doubt there is an easier way of doing this)

set.seed(1234)
fakereturns<-matrix(rnorm(10,1.01^(1/12)-1,0.01/(5*sqrt(12))),nrow=10,ncol=1)

for(i in 2:5){

  fakereturns <- cbind(fakereturns,matrix(rnorm(10,(1+i/100)^(1/12)-1,i/(500*sqrt(12))),nrow=10,ncol=1))
}

fakedates<-as.Date(as.yearmon(seq.Date(as.Date('2019-01-01'),by='month',length.out = 10)),frac=1)
R<-xts(fakereturns,fakedates)
names(R)<-c("stock1","stock2","stock3","stock4","stock5")

#Set up portfolio spec

pspec <- portfolio.spec(assets=names(R))
pspec <- add.constraint(pspec,type="weight_sum", min_sum=1, max_sum=1)
pspec <- add.constraint(pspec,type="box",min=rep(0,5),max=rep(1,5))

#Chart efficient frontier using historical data

portfolio<-pspec
eff_example <- create.EfficientFrontier(R=R, portfolio=portfolio, type="mean-StdDev")
chart.EfficientFrontier(eff_example, match.col="StdDev",type="l")

#(i) Specify much higher expected returns to make the frontier rise

exp.returns <- (1+seq(0.06,0.1,by=0.01))^(1/12)-1
num_assets <- length(exp.returns)
momentargs <- list()
momentargs$mu <-  matrix(exp.returns, nrow=num_assets, ncol=1 )

#Plot (i) as red circles -- why are these not above the first frontier?

eff_example_moments <- create.EfficientFrontier(R=R, portfolio=portfolio, type="mean-StdDev", momentargs=momentargs)
extract<-eff_example_moments$frontier
points(extract[,1]~extract[,2],col="red")

#(ii) Zero out the highest-returning asset's expected return to see what happens

exp.returns <- (1+c(0.01,0.02,0,0.04,0))^(1/12)-1
num_assets <- length(exp.returns)
momentargs <- list()
momentargs$mu <-  matrix(exp.returns, nrow=num_assets, ncol=1 )

#Plot (ii) as green circles -- why are these on the first frontier?

eff_example_moments <- create.EfficientFrontier(R=R, portfolio=portfolio, type="mean-StdDev", momentargs=momentargs)
extract<-eff_example_moments$frontier
points(extract[,1]~extract[,2],col="green")

#(iii) Reverse the order of expected returns to see what happens

exp.returns <- (1+seq(0.05,0.01,by=-0.01))^(1/12)-1
num_assets <- length(exp.returns)
momentargs <- list()
momentargs$mu <-  matrix(exp.returns, nrow=num_assets, ncol=1 )

#Plot (iii) as blue circles -- now we are off the original frontier, but why?

eff_example_moments <- create.EfficientFrontier(R=R, portfolio=portfolio, type="mean-StdDev", momentargs=momentargs)
extract<-eff_example_moments$frontier
points(extract[,1]~extract[,2],col="blue")
legend("bottomright",legend=c("Rtns increased by 0.05 annualised","Some zeroed out","Exp rtns reversed"),lwd=1,col=c(2,3,4))

1 Ответ

0 голосов
/ 24 апреля 2020

Отвечая на мой собственный вопрос. Я думаю, что фундаментальная проблема здесь заключается в том, что элемент $mu списка moments передается оптимизаторам только с помощью функции optimize.portfolio, если указана цель возврата. Если указана цель риска, $mu не используется.

Чтобы сделать эффективную границу, я взломал функцию optimize.portfolio, добавив код, который вставляет $mu, следующим образом:

 ## A line of existing code to show where I put this

 moments <- list(mean = rep(0, N))

 ## My added bit, straight after the above

if (!is.null(mout$mu)) {
  moments[["mean"]] <- as.vector(mout$mu)
}

## My bit ends

Затем я могу оптимизировать, сводя к минимуму стандартное отклонение для заданной целевой прибыли. Затем я перебираю целевые значения, чтобы создать эффективную границу (вместо использования функции create.EfficientFrontier).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...