R Studio中构建Fama-French模型动量因子的方法咨询
R高效实现Fama-French t-12至t-2动量因子
核心计算口径说明
t期动量因子值为跳过最近1个月(t-1月),回溯t-12至t-2共11个月的累计复合收益率。你的数据中
RET.USD为百分比收益率,计算前需除以100转换为小数收益率;如果使用调整后的收益指数RI计算,可直接通过指数比值得到累计收益,无需额外处理收益率。
方案1:data.table原生向量计算(速度最优,推荐大样本使用)
该方法完全基于向量运算,无逐窗口迭代开销,百万级行的面板数据可在毫秒级完成计算,远快于滚动apply类方法。
核心逻辑:区间累计收益 = 区间期末累计净值 / 区间期初前一期累计净值 - 1,不需要逐段连乘收益率。
library(data.table) setDT(DS.monthly) # 必须先按股票ID、日期升序排序,是所有时序计算的前提 setorder(DS.monthly, Id, Date) DS.monthly[, `:=`( # 百分比收益率转小数 RET = RET.USD / 100 ), by = Id] DS.monthly[, `:=`( # 累计净值序列 cum_nav = cumprod(1 + RET), # 动量计算:t-2期净值 / t-13期净值 -1,刚好对应t-12到t-2的累计收益 MOM = shift(cum_nav, n = 2) / shift(cum_nav, n = 13) - 1, # 如果直接用RI(收益指数)计算,可跳过cum_nav步骤,结果完全一致 MOM_RI = shift(RI, n = 2) / shift(RI, n = 13) - 1 ), by = Id]
注意:shift函数默认对排序后的数据按行取滞后值,前12个月因窗口不足会自动返回NA,符合因子计算的常规要求。
方案2:tidyverse + slider 滚动窗口实现
如果习惯tidyverse语法,可使用slider包的滚动计算函数,逻辑更直观:
library(dplyr) library(slider) DS.monthly <- DS.monthly |> arrange(Id, Date) |> group_by(Id) |> mutate( RET = RET.USD / 100, MOM = slide_dbl( .x = RET, .f = ~ prod(1 + .x) - 1, # 窗口内复合收益 .before = 11, # 包含当前行往前11行 .after = -2, # 排除当前行、当前行前1行(即t月、t-1月),窗口刚好覆盖t-2到t-12 .complete = TRUE # 仅窗口满11个观测时计算,不足则返回NA ) ) |> ungroup()
此前方案的问题说明
- 手动生成t_1到t_12列的实现:每生成一列就要做一次全表分组计算,冗余操作多、效率极低,且排序、列生成步骤多容易引入错位错误。
- 之前的
slide_dbl建议代码存在两个核心错误:- 未将百分比收益率转换为小数,计算结果完全偏离实际值
- 窗口偏移设置错误,无法准确对齐t-2到t-12的区间,且
last(cumprod(1+.x))的写法存在冗余
- 最初的全局
cumprod代码:是从上市日开始的全周期累计收益,无法截取指定11个月的区间,因此不适用。
注意事项
计算完成后可随机抽取单只股票,截取15-30行的区间,对比不同方法计算的MOM值,排除浮点精度误差后结果应完全一致。如果存在数据缺月,需要先按Id+Date补全连续月度序列再计算,避免行号错位导致结果错误。
内容的提问来源于stack exchange,提问作者Antisa Qipro
相关产品推荐
相关产品推荐

