如何在R中计算各ID事件日前后5天的Buy and Hold收益率?
R中事件窗口买入持有收益率计算完整方案
需求说明
- 按
ID分组,以EventDate为基准,计算事件日前5天至后5天共11个交易日的买入持有收益率 - 收益率公式:
(当日Price ÷ 事件日前6天的Price) - 1 - 为原数据表新增
BuyHoldReturn列,仅事件窗口内的日期计算收益率,其余日期设为NA
原数据示例
# 示例数据结构 data <- tibble( ID = c(1, 1, 1, 2), Date = as.Date(c("2011-03-06", "2011-03-07", "2011-03-12", "2011-06-19")), Price = c(10, 9, 12, 67), EventDate = c(NA, NA, as.Date("2011-03-12"), as.Date("2011-06-19")) )
预期结果示例
| ID | Date | Price | EventDate | BuyHoldReturn |
|---|---|---|---|---|
| 1 | 2011-03-07 | 9 | NA | -0.1 |
| 1 | 2011-03-12 | 12 | 2011-03-12 | 0.2 |
| 2 | 2011-06-14 | 57 | NA | 0.14 |
完整解决方案代码
library(dplyr) # 转换日期格式(确保Date和EventDate为标准日期类型) data$Date <- as.Date(data$Date) data$EventDate <- as.Date(data$EventDate) # 分组计算收益率 data_processed <- data %>% # 按ID和日期排序,保证交易日顺序正确 arrange(ID, Date) %>% group_by(ID) %>% # 提取当前ID的事件日(假设每个ID仅有1个非NA的EventDate) mutate(event_day = first(EventDate[!is.na(EventDate)])) %>% # 定位事件日在当前分组中的行索引 mutate(event_row = which(Date == event_day)) %>% # 获取事件日前6个交易日的基准价格(索引越界时设为NA) mutate(base_price = ifelse(event_row - 6 >= 1, Price[event_row - 6], NA)) %>% # 标记是否在事件窗口内(前5天至后5天) mutate(in_window = between(Date, event_day - 5, event_day + 5)) %>% # 计算买入持有收益率,仅窗口内日期计算,其余为NA mutate(BuyHoldReturn = ifelse(in_window, (Price / base_price) - 1, NA)) %>% # 移除辅助计算列 select(-event_day, -event_row, -in_window) %>% ungroup()
关键说明
- 排序要求:必须先按
ID和Date排序,保证交易日顺序正确,否则基准价格和窗口判断会出错 - 多事件日处理:如果一个
ID对应多个EventDate,需将group_by(ID)改为group_by(ID, EventDate),并调整事件窗口逻辑 - 边界情况处理:若事件日前6天无交易日(如新股上市),
base_price会返回NA,对应的收益率也为NA,可根据需求补充默认值或过滤逻辑 - 非交易日过滤:若原数据包含非交易日,需先通过
filter()过滤,确保仅保留交易日数据
内容的提问来源于stack exchange,提问作者catin
相关产品推荐
相关产品推荐

