Оптимизация портфеля с групповым ограничением с использованием PortfolioAnalytics - PullRequest
2 голосов
/ 07 апреля 2020

Моя цель - создать нейтральный к доллару и бета-нейтральный портфель, подверженный влиянию отдельных факторов, таких как размер, значение e cc ... Я попробовал , используя пакет .

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

setwd("C...Factor Investing/Data")
data <- read.csv("prova_mktcap.csv",sep=";")
stocks <- read.csv("prova_price.csv",sep=";")
library(tidyverse)
library(timetk)
library(quantmod)
library(stringr)
library(purrr)
library(tbl2xts)
library(PortfolioAnalytics)

##############################################################################
############################### DEFINING PTF COMPONENTS ######################
colnames(data) <- colnames(stocks)
stocks_xts <- as.xts(data[,-1], order.by=as.Date(data$Index,
                                               format="%d/%m/%Y"))
stocks_ret <- diff(log(stocks_xts))
data_xts <- as.xts(data[,-1], order.by=as.Date(data$Index,
                                                  format="%d/%m/%Y"))

data_tbk <- 
  data_xts %>%
  tk_tbl(preserve_index=TRUE, rename_index="date")%>%
  gather(asset, mktcap, -date) %>%
  group_by(date)
data_tbk$mktcap <- data_tbk$mktcap %>% as.numeric
data_tbk$asset <- str_replace(data_tbk$asset,"..MARKET.VALUE","cap") ##essentials


data_SIZE <-data_tbk %>% 
  group_by(date) %>%
  mutate(ptf = case_when(
    mktcap>=quantile(mktcap,0.8, na.rm=TRUE)~TRUE,
    mktcap<=quantile(mktcap,0.2, na.rm=TRUE)~FALSE,
    TRUE~NA
  ))   #when TRUE -> long portfolio
       #when FALSE -> short portfolio

Таким образом, я получил тибль data_SIZE со следующей структурой:

> str(data_SIZE)
Classes ‘grouped_df’, ‘tbl_df’, ‘tbl’ and 'data.frame': 131805 obs. of  4 variables:
 $ date  : Date, format: "2015-01-01" "2015-01-02" ...
 $ asset : chr  "X3M" "X3M" "X3M" "X3M" ...
 $ mktcap: num  104365 104200 101850 100764 101494 ...
 $ ptf   : logi  TRUE TRUE TRUE TRUE TRUE TRUE ...
 - attr(*, "groups")=Classes ‘tbl_df’, ‘tbl’ and 'data.frame':  261 obs. of  2 variables:
  ..$ date : Date, format: "2015-01-01" "2015-01-02" ...
  ..$ .rows:List of 261
  .. ..$ : int  1 262 523 784 1045 1306 1567 1828 2089 2350 ...

Он содержит для каждого месяца 2015 года и для всех акций в S & P500 его название эмитента, его рыночная капитализация и логическое значение, равное TRUE, если акция падает в этот конкретный день в верхнем квинтиле рыночных капиталов, и FALSE, если в тот же день она попадает в самый низкий квинтиль рыночных капиталов. В соответствии с этим критерием я собираюсь построить нейтральный к рынку портфель, подверженный фактору размера. Это пример, который я собираюсь воспроизвести для других факторов. Я храню названия акций, которые я собираюсь использовать, в списке, который содержит кадры данных с именами, соответствующими каждой дате.

long_components_size <- data_SIZE %>% filter(ptf==TRUE) %>% 
  select(asset,date) %>% group_by(date)
long_comps_size <- group_split(long_components_size, keep=FALSE)
names(long_comps_size) <- unique(long_components_size$date) #long 

short_components_size <- data_SIZE %>% filter(ptf==FALSE) %>% 
  select(asset,date) %>% group_by(date)
short_comps_size <- group_split(short_components_size, keep=FALSE)
names(short_comps_size) <- unique(short_components_size$date) #short

Теперь пришло время использовать фрейм данных stocks_ret для запуска оптимизации. Мне уже удалось совместить имена столбцов с именами, используемыми для различения рыночных ограничений.

> str(stocks_ret)
An ‘xts’ object on 2015-01-01/2015-12-31 containing:
  Data: num [1:261, 1:505] NA -0.00158 -0.02281 -0.01072 0.00722 ...
 - attr(*, "dimnames")=List of 2
  ..$ : NULL
  ..$ : chr [1:505] "X3M" "ABBOTT.LABORATORIES" "ABBVIE" "ABIOMED" ...
  Indexed by objects of class: [Date] TZ: UTC
  xts Attributes:  
 NULL

На этом этапе я запускаю , используя инструменты, предоставленные [Tag: PortfolioAnalytics], к сожалению, без успеха.

> port_size <- portfolio.spec(assets=colnames(stocks_ret))
> port_size <- add.constraint(port_size, type="group",
+                             groups=list(groupA=stocks_ret[,long_comps_size$`2015-01-01`$asset],
+                                         groupB=stocks_ret[,short_comps_size$`2015-01-01`$asset]),
+                             group_min=c(+1,-1),
+                             group_max=c(+1,-1))
> port_size <- add.constraint(port_size,type="weight_sum", min_sum=0,max_sum=0)
> port_size <- add.objective(port_size,type="return",name="mean")
> opt_size <- optimize.portfolio(R=stocks_ret, portfolio=port_size, 
+                                optimize_method="random")
Leverage constraint min_sum and max_sum are restrictive, 
              consider relaxing. e.g. 'full_investment' constraint should be min_sum=0.99 and max_sum=1.01
Error in seq.default(from = round(min, rounding), to = round(max, rounding),  : 
  'from' must be a finite number

Я знаю, что сделал Не добавляйте бета-нейтральное ограничение, но это уже испорчено. Позже я хотел бы установить add.objective с настраиваемой функцией, которая рассчитывает бета-версию на самом S & P500.

Если бы кто-нибудь смог дать мне понимание моей проблемы или других решений насмешки над Fama & French с нуля, это было бы большим вкладом в мою последнюю диссертацию.

...