我想知道如何按照金融文献中的典型方法在R中构建多空组合。
说我有以下数据:
Head():
# A tibble: 6 x 4
# Groups: assets [1]
assets returns id quantile
<fct> <dbl> <int> <chr>
1 AEIS -0.157 1 1
2 AEIS 0.107 2 1
3 AEIS 0.140 3 1
4 AEIS -0.111 4 1
5 AEIS -0.160 5 1
6 AEIS -0.00566 6 1
Tail():
# A tibble: 6 x 4
# Groups: assets [1]
assets returns id quantile
<fct> <dbl> <int> <chr>
1 GIB 0.0742 110 8
2 GIB 0.0201 111 8
3 GIB 0.0255 112 8
4 GIB 0.0446 113 8
5 GIB 0.0143 114 8
6 GIB 0.0537 115 8
一个人如何构造L-S投资组合,使我的投资组合/分位数为1
多头,而我的投资组合/分位数为8
空头?
数据/代码:
library(quantmod)
library(reshape2)
library(dplyr)
library(tidyr)
stocks <- c('AEIS', 'ABC', 'AMGN', 'BBY', 'HRB', 'BKE', 'CPLA', 'GIB')
getSymbols(stocks, from = "2010-01-01")
prices.data <- do.call(merge, lapply(stocks, function(x) Cl(get(x))))
returns <- setNames(do.call(cbind, lapply(prices.data, monthlyReturn)), stocks)
data <- returns %>%
data.frame() %>%
gather(assets, returns, 1:8, factor_key=TRUE) %>%
group_by(assets) %>%
mutate(id = 1:n(),
quantile = as.numeric(assets))
head(data)
答案 0 :(得分:1)
以下代码说明了如何进行LS收益计算(并希望能帮助其他热衷于了解LS投资组合收益如何计算的人。)
我还向您展示了分位数投资组合的全部含义-它通常是一项排名练习(例如,通过因子得分),这意味着某些股票多头,而其他股票则基于该得分。
很高兴看到有人可以在下面的LS计算中戳出一个孔,但是我的简单检查似乎表明它很好用。
library(quantmod)
library(reshape2)
library(dplyr)
library(tidyr)
if(!require(tbl2xts)) install.packages("tbl2xts")
if(!require(rmsfuns)) install.packages("rmsfuns")
stocks <- c('AEIS', 'ABC', 'AMGN', 'BBY', 'HRB', 'BKE', 'GIB') # CPLA doesn't fetch
getSymbols(stocks, from = "2016-01-01")
prices.data <- do.call(merge, lapply(stocks, function(x) Cl(get(x))))
returns <- setNames(do.call(cbind, lapply(prices.data, monthlyReturn)), stocks)
FactorInfo <-
tibble(assets = stocks, FactorScore = rnorm(n = length(stocks)))
data <-
returns %>% xts_tbl() %>%
gather(assets, returns, -date) %>%
left_join(., FactorInfo, by = "assets") %>%
mutate(RankPctile = percent_rank(FactorScore))
LongStocks <- data %>% select(assets, FactorScore) %>% unique() %>% arrange(FactorScore) %>% head(2) # pick two worst to short, as example
ShortStocks <- data %>% select(assets, FactorScore) %>% unique() %>% arrange(FactorScore) %>% tail(2) # pick two best to long, as example
Long_Port <- data %>% filter(assets %in% unique(LongStocks$assets)) %>% tbl_xts(cols_to_xts = "returns", spread_by = "assets")
Short_Port <- data %>% filter(assets %in% unique(ShortStocks$assets)) %>% tbl_xts(cols_to_xts = "returns", spread_by = "assets")
# Fully funded long-short position
W_Long <- data %>% filter(assets %in% unique(LongStocks$assets)) %>% filter(date == first(date)) %>% mutate(Weight = 1 / n()) %>% tbl_xts(cols_to_xts = "Weight", spread_by = "assets")
W_Short <- data %>% filter(assets %in% unique(ShortStocks$assets)) %>% filter(date == first(date)) %>% mutate(Weight = -1 / n()) %>% tbl_xts(cols_to_xts = "Weight", spread_by = "assets")
# Now calculate LS portfolio using PerformanceAnalytics:
# I recommend using rmsfuns::Safe_Return.portfolio, a wrapper for PerformanceAnalytics that makes it safer to use:
Port <- cbind(Long_Port, Short_Port)
Port_W <- cbind(W_Long, W_Short)
Port <-
rmsfuns::Safe_Return.portfolio(R = Port, weights = Port_W, lag_weights = TRUE, geometric = TRUE, verbose = TRUE)
LS_Port <- Port$returns %>% xts_tbl() %>% summarise(Cum = prod(1+portfolio.returns)) %>% .[[1]]
# Check correctness with direct calculation (can be done if only rebalanced once at the start):
all.equal( bind_rows(Long_Port %>% xts_tbl() %>% gather(assets, Ret, -date) %>% mutate(Weight = 1 / n_distinct(assets)),
Short_Port %>% xts_tbl() %>% gather(assets, Ret, -date) %>% mutate(Weight = -1 / n_distinct(assets))) %>%
group_by(assets, Weight) %>% summarise(Ret = prod(1+Ret) - 1) %>% ungroup() %>% summarise(Ret = sum(Ret*Weight)) %>% .[[1]],
LS_Port-1)
# To see your daily positions:
LS_Daily <- Port$EOP.Value %>% xts_tbl %>% gather(stocks, eop.val, -date) %>% group_by(date) %>% summarise(return = sum(eop.val))
# Of course - you can further rebalance to other positions by adjusting Port_W