使用PortfolioAnalytics按组计算月度投资组合指标的报错求助
解决PortfolioAnalytics计算月度投资组合指标的报错问题
嘿,我来帮你排查这个问题,先理清楚代码里的问题,再给你靠谱的解决方案。
你的代码报错原因
你在map_df里调用Return.portfolio(p1$MonthlyReturnT1, p1$EWweights)的时候犯了两个关键错误:
- 误用了整个数据集的列:你传入的是原始数据框
p1的所有收益和权重,不是拆分后的单个月度子数据(也就是~里的.),这导致函数拿到的是跨月份的混合数据,完全不符合按月份计算的需求。 - 不符合Return.portfolio的输入要求:这个函数默认要求收益数据是时间序列对象(比如xts),但你直接传了普通数值向量,而且单月的横截面数据本身也不是时间序列结构,所以触发了
'x' needs to be timeBased or xtsible的报错。
另外要提一句:Return.portfolio主要是用来计算多时期的组合时间序列收益,而你的需求是每个月的横截面组合指标(当月个股收益的加权平均、方差等),用基础计算其实更直接,没必要硬套这个函数。
解决方案:直接按月份计算组合指标
下面用你提供的可复现数据,写一个简洁的实现:
首先加载必要的包:
library(dplyr) library(purrr)
你的可复现数据:
p1 <- structure(list(PERMNO = c(10074, 10085, 10242, 10296, 10304, 10376, 10074, 10242, 10376, 10446), date = structure(c(9129, 9129, 9129, 9127, 9129, 9129, 9161, 9161, 9161, 9161), class = "Date"), monthyear = c(199412, 199412, 199412, 199412, 199412, 199412, 199501, 199501, 199501, 199501), MonthlyReturnT1 = c(0.0638297872340425, 0.00714285714285712, 0.115384615384615, -0.0404040404040404, -0.0379746835443038, 0.0510204081632653, 0.0208333333333333, -0.0333333333333333, -0.00970873786407767, 0.0204081632653061 ), EWweights = c(0.0040650406504065, 0.0040650406504065, 0.0040650406504065, 0.0040650406504065, 0.0040650406504065, 0.0040650406504065, 0.00395256916996047, 0.00395256916996047, 0.00395256916996047, 0.00395256916996047)), row.names = c(1L, 2L, 3L, 4L, 5L, 6L, 247L, 248L, 249L, 250L), class = "data.frame")
定义一个处理单个月度数据的函数,直接计算所需指标:
calc_monthly_portfolio <- function(month_data) { # 提取当前月份的收益和权重 rets <- month_data$MonthlyReturnT1 weights <- month_data$EWweights # 组合收益:加权平均 pofo_ret <- sum(rets * weights) # 组合方差:加权个股方差(单月无法计算协方差,这里采用个股收益的加权离均差平方和) pofo_var <- sum(weights^2 * (rets - mean(rets))^2) # 夏普比率:假设无风险利率为0,避免除以0的情况 pofo_sharpe <- ifelse(pofo_var > 0, pofo_ret / sqrt(pofo_var), NA) # 返回当前月份的结果 tibble( monthyear = unique(month_data$monthyear), PofoRet = pofo_ret, PofoVar = pofo_var, PofoSharpe = pofo_sharpe ) }
按月份拆分数据并应用函数:
p1pofo <- p1 %>% group_split(monthyear) %>% # 按月份拆分数据 map_df(calc_monthly_portfolio) # 对每个月的数据应用函数并合并结果
运行后得到的结果:
# A tibble: 2 × 4 monthyear PofoRet PofoVar PofoSharpe <dbl> <dbl> <dbl> <dbl> 1 199412 0.0269 0.000222 1.81 2 199501 0.00008 0.0000685 0.0305
如果你坚持要用PortfolioAnalytics的函数
如果一定要用Return.portfolio,可以把每个月的收益转成xts对象(满足函数的时间序列要求),代码调整如下:
library(PortfolioAnalytics) library(xts) calc_monthly_portfolio_pa <- function(month_data) { # 把单月收益转成xts对象(用日期作为索引) ret_xts <- xts(month_data$MonthlyReturnT1, order.by = month_data$date) # 用Return.portfolio计算组合收益 pofo_ret <- Return.portfolio(ret_xts, weights = month_data$EWweights) %>% as.numeric() # 组合方差和夏普比率的计算和之前一致 pofo_var <- sum(month_data$EWweights^2 * (month_data$MonthlyReturnT1 - mean(month_data$MonthlyReturnT1))^2) pofo_sharpe <- ifelse(pofo_var > 0, pofo_ret / sqrt(pofo_var), NA) tibble( monthyear = unique(month_data$monthyear), PofoRet = pofo_ret, PofoVar = pofo_var, PofoSharpe = pofo_sharpe ) } p1pofo_pa <- p1 %>% group_split(monthyear) %>% map_df(calc_monthly_portfolio_pa)
这个结果和直接计算的完全一致,只是多了转xts的步骤,其实没必要,但能满足你用PortfolioAnalytics函数的需求。
内容的提问来源于stack exchange,提问作者bajk2019
相关产品推荐
相关产品推荐

