在 R 中複製動量策略(UMD/MOM、SUE 和 CAR3)
我正在寫關於動量策略的碩士論文,包括價格動量(UMD/MOM)和兩種基本動量策略(SUE 和 CAR3)。現在我正在嘗試創建三個動量因子,以便比較它們在 1975-2012 年的表現。UMD/MOM 因子是 Fama-French 已經建構的因子。該文件可以在法語網站上看到:https ://mba.tuck.dartmouth.edu/pages/faculty/ken.french/Data_Library/det_mom_factor.html
我在建構 MOM 因子時遵循 Fama-French 的方法,然後在創建 SUE 和 CAR3 因子時嘗試遵循完全相同的過程,就像 Robert Novy-Marx 在他 2015 年的文章“從根本上說,動量是基本動量”中一樣:http ://rnm.simon.rochester.edu/research/FMFM.pdf 。我的數據通過以下程式碼直接從 WRDS 收集到 R:https ://drive.google.com/file/d/0BxvBvE2V-dFTVnZuLUFhZWNuazA/view?fbclid=IwAR0-uPDl1-kzRyugIVePTtIFxMiM5jQbbWqE9VxIdMftrs4adJ_zDGuh4Go
Novy-Marx (2015) 在 p 上創建了一個因子表現圖。9 這是我想要複製的數字。我的 MOM 和 CAR3 結果與 Fama-French 和 Robert 非常相似。下圖是我的結果,其中 UMD 因子是我建構的,MOM 因子是我從 Fama-French 下載的。這清楚地表明我已經能夠以幾乎 1:1 的比例複製 UMD 因子,並且 CAR3 也與 Novy-Marx (2015) 非常相似。
但是,當我將 SUE 包含到圖表中時,它會導致:
但正如您所見,SUE 高得不切實際。由於建構因子性能的過程與 UMD 和 CAR3 完全相同,這意味著問題必須與我對 SUE 本身的計算有關。因此,我需要一些幫助來檢查問題到底發生在哪裡。
在計算 SUE 時,我遵循 Novy-Marx (2015)。他將 SUE 定義為“最近的每股收益同比變化,按過去八次公告中這些收益創新的標準差衡量,但要求在兩年視窗內至少觀察六次公告."。我將嘗試一步一步地寫出我到底在做什麼:
第 1 步:我從 Compustat 下載季度數據,包括變數 DATADATE、GVKEY 和 EPSPXQ(每股收益(基本)/不包括特殊項目)。
res <- dbSendQuery(wrds,"select gvkey, datadate, epspxq from comp.fundq where INDFMT='INDL' and DATAFMT='STD' and CONSOL='C' and POPSRC='D'") comp.fundq <- dbFetch(res, n = -1)
第 2 步:我按 datadate 和 gvkey 排列數據,以確保數據以正確的順序排列,然後將 EPSPXQ 滯後 4 個季度。
comp.data <- comp.data %>% arrange(datadate, gvkey) %>% group_by(gvkey) %>% mutate(lag.eps = dplyr::lag(epspxq, n = 4, default = NA))
第 3 步:我通過以下方式計算收益創新
comp.data$ei <- comp.data$epspxq-comp.data$lag.eps
第 4 步:我計算滾動標準。在步驟 3 中計算的最近 8 個公告(寬度 = 8)的收益創新偏差,其標準要求至少 6 個非 NA 觀察值(部分 = 6)
FUN <- function(x) if (length(na.omit(x)) >= 6) sd(x, na.rm = TRUE) else NA roll1 <- function(z) rollapplyr(z, width = 8, FUN = FUN, fill = NA, partial = 6) comp.data <- comp.data %>% arrange(datadate, gvkey) %>% transform(comp.data, roll1 = ave(ei, gvkey, FUN = roll1))
第 5 步:我通過以下方式計算 SUE
comp.data$sue <- comp.data$ei/comp.data$roll1
第 6 步:我從 WRDS 下載 CCM 數據,作為將 Compustat 數據與 CRSP 數據合併的一個步驟:
res <- dbSendQuery(wrds,"select GVKEY, LPERMNO, LINKDT, LINKENDDT, LINKTYPE, LINKPRIM from crsp.ccmxpf_lnkhist") ccm <- dbFetch(res, n = -1)
第 7 步:我將 Compustat 數據集 comp.data(包括我的新 SUE 變數)與 CCM 合併:
ccm.comp <- ccm %>% filter(linktype %in% c("LU", "LC", "LS")) %>% filter(linkprim %in% c("P", "C", "J")) %>% merge(comp.data, by="gvkey") %>% mutate(datadate = as.Date(datadate), permno = as.factor(lpermno), linkdt = as.Date(linkdt), linkenddt = as.Date(linkenddt), linktype = factor(linktype, levels=c("LC", "LU", "LS")), linkprim = factor(linkprim, levels=c("P", "C", "J"))) %>% filter(datadate >= linkdt & (datadate <= linkenddt | is.na(linkenddt))) %>% arrange(datadate, permno, linktype, linkprim) %>% distinct(datadate, permno, .keep_all = TRUE)
第 8 步:我在合併後清理我的數據:
ccm.comp.cln <- ccm.comp %>% arrange(datadate, permno) %>% select(datadate, permno, sue) %>% mutate_if(is.numeric, funs(ifelse(is.infinite(.), NA, .))) %>% mutate_if(is.numeric, funs(round(., 5))) ccm.comp.cln$datadate <- strptime(as.character(ccm.comp.cln$datadate), "%Y-%m-%d") ccm.comp.cln$datadate <- format(ccm.comp.cln$datadate,"%Y%m")
第 9 步:我載入 CRSP 數據並以與 Fama-French 相同的方式對其進行清理:“”…所有在美國註冊成立並在 NYSE、AMEX 或 NASDAQ 上市且 CRSP 股票程式碼為 10 或t 月初 11 日,t 月初股票和價格數據良好,t 月份收益數據良好。這也包括退市收益的處理。
第 10 步:我將我的 CCM-Compustat 數據與我的 CRSP 數據合併:
na_locf_until = function(x, n) { l <- cumsum(! is.na(x)) c(NA, x[! is.na(x)])[replace(l, ave(l, l, FUN=seq_along) > (n+1), 0) + 1] } crsp.comp <- merge(x = crsp.data, y = ccm.comp.cln, by.x = c("permno", "date"), by.y = c("permno", "datadate"), all.x = TRUE)
誰能幫我確定哪裡可能出現問題?
如果這不是問題,請為聽起來像地獄般的光顧道歉……但是與您的 EPS 數據相關的日期是否指(1)有問題的會計期間,或(2)這些報告的日期?
因此,如果(例如)通用電氣或摩根大通在情人節報告 2020 年第四季度日曆,這是 2020 年 12 月 31 日還是 2021 年 2 月 14 日?
如果是前者,那麼使用這個日期對價格然後有效地增持您的投資組合以實現正收益節拍,反之亦然避免負失誤……這將產生您最初執行似乎顯示的那種虛假阿爾法。在這種情況下,如果您採用倒數第二次報告的每股收益而不是第五次,您會得到積極但更現實的結果嗎?