Диаграмма аналитики портфеля R.EfficientFrontier function

Я пытаюсь использовать функцию chart.EfficientFrontier из пакета portfolioanalytics в R, чтобы построить эффективный граничный объект, который я создал, но он продолжает давать сбой. По сути, я пытаюсь найти границу, которая минимизирует аннализированное стандартное отклонение. В конце концов, когда я получу эту работу, я бы также хотел максимизировать годовой доход.

Сначала я создал функцию стандартного отклонения в годовом исчислении, используя этот код

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

Кто-нибудь знает, почему это так? Когда я использую сводку (prt.ef), я могу видеть вес, но почему происходит сбой функции chart.EfficientFrontier?

4 ответа

Как и предполагал @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")

В добавление к комментариям Роберта, расчет оптимизации с ежемесячной доходностью является задачей квадратичного программирования с линейными ограничениями. когда mean это return цель и StdDev или же var это risk задача, optimize.portfolio а также create.EfficientFrontier выберите ROI метод в качестве решателя, который использует solve.QP, эффективный решатель для такого рода проблем. Когда risk цель изменена на pasdэти функции не распознают это как проблему QP, поэтому используйте DEoptim общий решатель нелинейных задач, возможно, лучше подходит для решения невыпуклых задач, чем выпуклых задач QP. См. Дифференциальная эволюция с 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 и показано на графике ниже.

введите описание изображения здесь

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

Не находит причину ошибки, но установка пределов частично работает!

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)

Хорошо, так что я попробовал pasd функция, которую предложил WaltS, и график. Эффективная граница, казалось, работала, но она дала мне неровную линию, а не плавную линию.

Теперь я создал функцию возврата в годовом исчислении, используя этот код:

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
Другие вопросы по тегам