# Construct monthly BEA industry returns for the same period of years codes = Sectoring(sql, f"bea{vintage}", fillna='') naics = pstat.build_lookup('lpermno', 'naics', fillna=0) caps, counts, rets = [], [], [] for year in years: date = bd.endyr(year - 1) univ = crsp.get_universe(date) univ['bea'] = codes[naics(univ.index, date)] univ = univ[univ['bea'].ne('')] grouped = univ.groupby('bea') caps.append(grouped['cap'].sum().rename(year)) counts.append(grouped['cap'].count().rename(year)) months = bd.date_range(date, bd.endyr(year), 'endmo') for rebaldate, end in zip(months[:-1], months[1:]): r = pd.concat([crsp.get_ret(bd.begmo(end), end), crsp.get_cap(rebaldate, use_permco=False), univ['bea']], axis=1, join='inner').dropna() grp = r.groupby('bea') # industry ret is sum of weighted rets r['wtdret'] = r['ret'].mul(r['cap'].div(grp['cap'].transform('sum'))) rets.append(grp['wtdret'].sum(min_count=1).rename(end)) print(end, len(r), r['wtdret'].sum() / len(grp)) # collect and average market caps, counts and returns caps = pd.concat(caps, axis=1).mean(axis=1) # average cap over years counts = pd.concat(counts, axis=1).mean(axis=1) # average count rets = pd.concat(rets, axis=1) # create node variables: count and cap (will take logs of) nodevars = pd.concat([caps.rename('cap'), counts.rename('count')], axis=1) rets = rets.T[nodevars.index] # ensure same order of industries
end = wd.endwk(beg) # ending date of holding week prcdate = bd.offset(start, -1) # require price available at start of week prcyear = (prcdate // 10000) * 10000 if prcyear != year: # retrieve new batch of prices each new year year = prcyear prc = crsp.get_range('daily', 'prc', 'date', year + 101, year + 1231, use_cache=True) X = prc[prc.index.get_level_values('date') == prcdate]\ .reset_index()\ .set_index('permno')\ .join(crsp.get_ret(start,rebaldate).reindex(univ.index))\ .dropna() # retrieve prior week's returns, require start price Y = crsp.get_ret(beg, end).reindex(X.index).fillna(0) # gross return Z = crsp.get_ret(bd.offset(beg, 1), end).reindex(X.index).fillna(0) # net ret z = Z['ret'] y = Y['ret'] x = (X['ret'].mean() - X['ret']) / (X['ret'].std(ddof=0) * len(X) ) # standardize res = res.append( DataFrame( { 'ret': x.dot(y), 'ic': x.corr(y), 'n': len(Y),
if 'monthly' in testable: if regenerate: beg, end = 19251231, LAST_DATE intervals = {'mom12m': (2,12), 'mom36m': (13,36), 'mom6m': (2,6), 'mom1m': (1,1)} for label, past in intervals.items(): out = DataFrame() for rebaldate in bd.date_range(bd.endmo(beg, past[1]), end, 'endmo'): start = bd.endmo(rebaldate, -past[1]) beg1 = bd.offset(start, 1) end1 = bd.endmo(rebaldate, 1-past[0]) df = crsp.get_universe(end1) df['start'] = crsp.get_section(dataset='monthly', fields=['ret'], date_field='date', date=start)\ .reindex(df.index) df[label] = crsp.get_ret(beg1, end1).reindex(df.index) df['permno'] = df.index df['rebaldate'] = rebaldate df = df.dropna(subset=['start']) out = out.append(df[['rebaldate', 'permno', label]], ignore_index=True) # append rows n = signals.write(out, label, overwrite=True) beg, end = 19270101, LAST_DATE columns = ['chmom', 'divyld', 'indmom'] out = DataFrame() for rebaldate in bd.date_range(beg, end, 'endmo'): start = bd.endmo(rebaldate, -12) beg1 = bd.offset(start, 1) end1 = bd.endmo(rebaldate, -6) beg2 = bd.offset(end1, 1)
window=12, months=[6], rebals=rebals)['holdings'] # Compute MOM momentum factor label = 'mom' past = (2, 12) df = [] # collect each month's momentum signal values rebalend = bd.endmo(LAST_DATE, -1) for rebaldate in bd.date_range(rebalbeg, rebalend, 'endmo'): beg = bd.endmo(rebaldate, -past[1]) # require price at this date start = bd.offset(beg, 1) # start date, inclusive, of signal end = bd.endmo(rebaldate, 1 - past[0]) # end date of signal p = [ crsp.get_universe(rebaldate), # retrieve prices and construct signal crsp.get_ret(start, end)['ret'].rename(label), crsp.get_section('monthly', ['prc'], 'date', beg)['prc'].rename('beg'), crsp.get_section('monthly', ['prc'], 'date', end)['prc'].rename('end') ] q = pd.concat(p, axis=1, join='inner').reset_index().dropna() q['rebaldate'] = rebaldate df.append(q[['permno', 'rebaldate', label]]) print(rebaldate, len(df), len(q)) df = pd.concat(df) signals = chunk_signal(df) holdings[label] = famafrench_sorts(crsp, label, signals, rebalbeg, rebalend, window=0,
- same year filings [yr]0101:[yr]1231 = bd.begyr(caldate) to caldate - lagged [yr+1]0401:[yr+2]0331 = bd.begmo(caldate,4) - bd.endmo(caldate,15) """ for ifig, key in enumerate(['mdasent', 'mdachg', 'mdacos']): ret1 = {} # to collect year-ahead spread returns ret0 = {} # to collect current-year spread returns for year in sorted(np.unique(data['year'])): # loop over years # compute current year spread returns beg = bd.begyr(year) end = bd.endyr(year) univ = data[data['year'] == year]\ .dropna(subset=[key])\ .set_index('permno')\ .join(crsp.get_cap(bd.offset(beg, -1)), how='inner')\ .join(crsp.get_ret(beg, end, delist=True), how='left') if len(univ): sub = fractiles(univ[key], [20, 80]) pos = weighted_average(univ.loc[sub == 1, ['cap', 'ret']], 'cap')['ret'] neg = weighted_average(univ.loc[sub == 3, ['cap', 'ret']], 'cap')['ret'] ret0[end] = { 'ret': pos - neg, 'npos': sum(sub == 1), 'nneg': sum(sub == 3) } if ECHO: print(end, len(univ), pos, neg) # compute year ahead spread returns
## Construct Mom # Load monthly universe and stock returns from CRSP. # Signal is stocks' total return from 12 months ago, skipping most recent month # Construct 2-way portfolio sorts, and backtest returns label, benchname, past, leverage = 'mom', 'Mom(mo)', (2, 12), 1 rebalbeg, rebalend = 19260101, LAST_DATE df = [] # collect each month's momentum signal values for rebaldate in bd.date_range(rebalbeg, rebalend, 'endmo'): beg = bd.endmo(rebaldate, -past[1]) # require price at this date start = bd.offset(beg, 1) # start date, inclusive, of signal end = bd.endmo(rebaldate, 1 - past[0]) # end date of signal p = [ crsp.get_universe(rebaldate), # retrieve prices and construct signal crsp.get_ret(start, end)['ret'].rename(label), crsp.get_section('monthly', ['prc'], 'date', beg)['prc'].rename('beg'), crsp.get_section('monthly', ['prc'], 'date', end)['prc'].rename('end') ] q = pd.concat(p, axis=1, join='inner').reset_index().dropna() q['rebaldate'] = rebaldate df.append(q[['permno', 'rebaldate', label]]) print(rebaldate, len(df), len(q)) df = pd.concat(df) signals.write(df, label, overwrite=True) portfolios = famafrench_sorts(crsp, label, signals, rebalbeg, rebalend, window=0,