Я пытаюсь выполнить анализ атрибуции портфеля акций с помощью функции brinson
в пакете pa
.До сих пор я только мог заставить эту функцию работать, используя встроенный набор данных jan
.Возможно, я не совсем уверен, что именно должна работать эта функция, но, как я понимаю, для этого мне нужно сначала собрать нужные мне данные из нескольких источников.
library(readxl)
library(pa)
library(tidyquant)
library(Quandl)
library(quantmod)
library(rvest)
library(tidyverse)
library(stringr)
coreUS <- Quandl.datatable('SHARADAR/SF1', paginate=TRUE)
CoreUS содержит подавляющее большинство компанийперечислены в NYSE NAZDAQ и AMEX.
#This excel file has the stocks I need to run the function on.
ndr_Raw <- read_xlsx("NDRLS012019.xlsx", skip = 3, n_max = 51)
Это выглядит так:
head(ndr_Raw)
symbol name weights
<chr> <chr> <dbl>
1 MOS Mosaic Company 0.015
2 NGVT Ingevity Corporation 0.015
3 KWR Quaker Chemical Corp 0.015
4 ENS EnerSys 0.015
5 FLS Flowserve Corporation 0.015
6 DCI Donaldson Company Inc 0.015
NYSE <- tq_exchange("NYSE")
NASDAQ <- tq_exchange("NASDAQ")
AMEX <- tq_exchange("AMEX")
Привязка ndr_Raw
, NYSE
и NASDAQ
к одному и тому же фрейму данных.
ndr <- ndr_Raw %>%
inner_join(rbind(NYSE, NASDAQ), by = c("symbol"))
Возьмите нужные столбцы
ndr2 <- select(ndr, symbol, sector, industry, weights)
Получите месячные доходности по акциям NDR
ndr3 <- merge(ndr2, tq_get(ndr2$symbol, get = "stock.prices", from =
"2019-01-01") %>% group_by(symbol) %>%
tq_transmute(adjusted, periodReturn, period = "monthly"), by = "symbol")
#Download S&P stock data
url <- "https://www.slickcharts.com/sp500"
sp500 <- url %>%
read_html() %>%
html_nodes(xpath = '/html/body/div/div[2]/div[1]/div/div/table') %>%
html_table()
sp500 <- sp500[[1]]
В примере jan
их столбец benchmark
складываетсяк 1, а не к 100, так что ...
sp500$Weight <- sp500$Weight/100
#Get stock data for all Core US stocks.
coreUS_slim <- tq_get(unique(coreUS$ticker), get = "stock.prices", from = "2019-01-01")
#Transmute the date into monthly returns
coreUS_slim2 <- na.omit(coreUS_slim) %>% group_by(symbol) %>%
tq_transmute(adjusted, periodReturn, period = "monthly")
#subset coreUS for just the rows containing the NDR stocks
coreNDR <- coreUS_slim2[coreUS_slim2$symbol %in% ndr3$symbol,]
#Finds the missing stocks not in coreUS
missingSymbols <- setdiff(ndr3$symbol, coreNDR$symbol)
#Download missing stock data and transmute it to monthly returns. Method differs depending on if there are one or more missing stocks.
if(length(missingSymbols) > 1)
{
missingSymbols_Data <- tq_get(missingSymbols, get = "stock.prices", from = "2019-01-01") %>% group_by(symbol) %>%
tq_transmute(adjusted, periodReturn, period = "monthly")
} else
{
missingSymbols_Data <- tq_get(missingSymbols, get = "stock.prices", from = "2019-01-01") %>%
tq_transmute(adjusted, periodReturn, period = "monthly")
missingSymbols_Data$symbol <- missingSymbols
missingSymbols_Data <- missingSymbols_Data[,c(3, 1:2)]
}
#Binds missing data to primary data set.
coreUS_slim3 <- coreUS_slim2
coreUS_slim3 <- bind_rows(coreUS_slim2, missingSymbols_Data)
#Takes subset of coreUS for stocks that are in the S&P
spSubset <- coreUS_slim3[coreUS_slim3$symbol %in% sp500$Symbol,]
#Finds missing S&P stocks
missingSP <- setdiff(sp500$Symbol, coreUS_slim3$symbol)
#Corrects them into a format recognizable by tq_get() function
missingSP <- gsub(pattern = "\\.", replacement = "-", x = missingSP)
#Download missing stock data and transmute it to monthly returns. Method differs depending on if there are one or more missing stocks.
if(length(missingSP) > 1)
{
missingSP_Data <- tq_get(missingSP, get = "stock.prices", from = "2019-01-01") %>% group_by(symbol) %>%
tq_transmute(adjusted, periodReturn, period = "monthly")
} else
{
missingSP_Data <- tq_get(missingSP, get = "stock.prices", from = "2019-01-01") %>%
tq_transmute(adjusted, periodReturn, period = "monthly")
missingSP_Data$symbol <- missingSP
missingSP_Data <- missingSP_Data[,c(3, 1:2)]
}
#Binds missing S&P data to primary data set
spsubset2 <- bind_rows(spSubset, missingSP_Data)
coreUS_slim3 <- bind_rows(coreUS_slim3, missingSP_Data)
#Creates portfolio column composed entirely of zeros
coreUS_slim3$portfolio <- 0
#subsets coreUS for stocks in the NDR data set and sets their portfolio value to 0.015
coreUS_slim3[coreUS_slim3$symbol %in% ndr3$symbol,]$portfolio <- 0.015
coreUS_slim4 <- coreUS_slim3
##Replaces dots with dashes for tq_get()
spsubset2$symbol <- gsub(pattern = "\\.", replacement = "-", x = spsubset2$symbol)
sp500$Symbol <- gsub(pattern = "\\.", replacement = "-", x = sp500$Symbol)
#subsets all values for the month of january.
coreUSjan <- subset(coreUS_slim4, format.Date(date, "%m") == "01")
#subsets january coreUS data for S&P stocks
coreSP <- coreUSjan[coreUSjan$symbol %in% spsubset2$symbol,]
colnames(sp500)[3] <- "symbol"
#Gets weightings for S&P stocks
coreSP2 <- merge(coreSP, sp500, by = "symbol")
coreSP2 <- coreSP2[, c("symbol", "date", "monthly.returns", "portfolio", "Weight")]
colnames(coreSP2)[5] <- "benchmark"
#Merges S&P weighting to main january dataset.
coreUSjan2 <- merge(coreUSjan, coreSP2, by = c("symbol", "date", "monthly.returns", "portfolio"), all = TRUE)
coreUSjan2$benchmark[is.na(coreUSjan2$benchmark)] <- 0
ndrJan <- subset(ndr3, format.Date(date, "%m") == "01")
NYSE_NASDAQ <- merge(NYSE, NASDAQ, all = TRUE)
NYSE_NASDAQ_AMEX <- merge(NYSE_NASDAQ, AMEX, all = TRUE)
coreUSjan3 <- merge(coreUSjan2, NYSE_NASDAQ_AMEX, all.x = TRUE)
coreUSjan3 <- coreUSjan3[, c(1:5, 10:11)]
Я считаю, что я получил свои данные до такой степени, что я могу использовать функцию brinson
, но когда я это делаю, выдается ошибка.
coreUSjan4 <- brinson(x = coreUSjan3, date.var = "date", cat.var = "sector", bench.weight = "benchmark", portfolio.weight = "portfolio",
ret.var = "monthly.returns")
Error in ret.bench/weight.bench : non-conformable arrays
Используемый мною фрейм данных coreUSjan3
выглядит следующим образом: портфель
> head(coreUSjan3)
symbol date monthly.returns portfolio benchmark sector industry
1 A 2019-01-31 0.15771047 0 0.00105024 Capital Goods Biotechnology: Laboratory Analytical Instruments
2 AA 2019-01-31 0.13109756 0 0.00000000 Basic Industries Aluminum
3 AAC 2019-01-31 0.48466258 0 0.00000000 Health Care Medical Specialities
4 AAL 2019-01-31 0.10129314 0 0.00065235 Transportation Air Freight/Delivery Services
5 AAMC 2019-01-31 -0.10563146 0 0.00000000 Finance Real Estate
6 AAME 2019-01-31 0.08433735 0 0.00000000 Finance Life Insurance
содержит веса, указанные в файле xlsx в 0,015 для их соответствующего запаса в coreUSjan3
, а остальныезначения равны 0. В столбце эталонных значений содержатся весовые коэффициенты для индекса S & P500 и непринадлежащие S & P получают 0.