R中的多空投资组合计算

时间:2019-06-29 23:04:28

标签: r quantmod

我想知道如何按照金融文献中的典型方法在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)

1 个答案:

答案 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