
价变共振
本文,笔者将复现一下招商证券任曈老师的研报《“青出于蓝”系列研究之九-基于分钟数据的价变共振因子》。
在此之前,笔者复现了这篇研报中的领先成交额异动因子,这个因子在分层回测上的表现非常不错。
于是,让笔者对同研报中的另外一个因子也充满了兴趣。
计算步骤和代码
先来看看这个因子的计算步骤和代码,然后看看《因子日历》中对这个因子的说明。
1
计算步骤
该因子的计算一共5个步骤。
第一步,计算个股收益率最高/最低5分钟市场收益率的标准差,记为std_max和std_min。
第二步,计算个股收益率最高/最低5分钟市场等权收益率的均值,记为rm_max和rm_min。
第三步,对rm_max在截面上正序排名,rm_min在截面上逆序排名。
第四步,将排名后的rm_max和rm_min分别除以std_max和std_min。
第五步,对过去5个交易日的因子计算均值。(这里笔者为了和之前的因子进行对比,还是取了21个交易日)
2
代码
def process_single_day(self, idx):# 加载当日分钟数据file_name = self.files[idx]date_str = file_name.split('.')[0]cur_time = pd.to_datetime(date_str) + timedelta(hours=15)full_path = os.path.join(self.file_pth, file_name)data = BaseDataLoader.load_data(full_path, fields=['close', 'turnover']).to_dataframes()rtn = data['close'].pct_change()mkt = rtn.mean(axis=1)mkt_sigma = rtn.std(axis=1)resi = []for i in range(len(rtn.columns)):resi.append(self.cal_resi(rtn.iloc[:, i], mkt))resi = pd.concat(resi, axis=1)resi = resi.reindex(rtn.index)res = []for q in [1 / 48, 47 / 48]:if q == 1 / 48:flag = rtn < rtn.quantile(q)resi_flag = resi < resi.quantile(q)else:flag = rtn > rtn.quantile(q)resi_flag = resi > resi.quantile(q)rtn_mean_factor = np.nanmean(mkt.values.reshape(-1, 1) * np.where(flag, 1.0, np.nan), axis=0)rtn_mean_factor = pd.Series(rtn_mean_factor, index=rtn.columns)resi_mean_factor = np.nanmean(mkt.values.reshape(-1, 1) * np.where(resi_flag, 1.0, np.nan), axis=0)resi_mean_factor = pd.Series(resi_mean_factor, index=rtn.columns)if q == 1 / 48:tmp_rtn = rtn_mean_factor.rank(pct=True, ascending=False)tmp_resi = resi_mean_factor.rank(pct=True, ascending=False)else:tmp_rtn = rtn_mean_factor.rank(pct=True)tmp_resi = resi_mean_factor.rank(pct=True)rtn_sigma = np.nanmean(mkt_sigma.values.reshape(-1, 1) * np.where(flag, 1.0, np.nan), axis=0)resi_sigma = np.nanmean(mkt_sigma.values.reshape(-1, 1) * np.where(resi_flag, 1.0, np.nan), axis=0)res += [tmp_rtn / pd.Series(rtn_sigma, index=rtn.columns),tmp_resi / pd.Series(resi_sigma, index=rtn.columns)]res = pd.concat(res, axis=1)res.columns = ['co_min', 'co_min_resi', 'co_max', 'co_max_resi']res['datetime'] = cur_timereturn res
在复现的时候,笔者不仅考虑了收益率来计算这个因子,还将其替换为残差收益率进行了一次尝试。
前14行,主要就是读取数据。
第15行,计算残差收益率。
第17-37行,计算因子。这里,笔者没有直接取最大或者最小的5分钟,而是按照分位数来计算,有两个原因。
第一,这样更简洁,不需要用for循环遍历每一个标的。
第二,这样可以不纠结于收益率相同的时候取哪一分钟。
第19-20行,获取最小的1/48分位数。
第22-23行,获取最大的1/48分位数。
第24-27行,计算rm_min或rm_max。
第29-30行,对于最小的1/48分位数倒序排列。
第32-33行,对于最大的1/48分位数正序排列。
第34-35行,用排序的收益率除以标准差,得到了日频的因子值。
3
因子逻辑
在因子日历中,这篇研报占据了多页。
先来看看co_min,即rm_min/std_min因子的逻辑。
rm_min刻画了个股与市场趋势的一致性,因子值越小,说明个股是在市场表现较差时同步出现价格下跌,与全市场下跌趋势一致,个股与市场形成有效共振,股价下跌可能是市场恐慌性错杀带来的,未来股价更容易被修正,未来收益表现较好;std_min刻画了市场整本收益的分歧度,分歧度越小,市场趋势更具市场代表性,个胶与市场共振越有效,将其叠加后有助于提升rm_min的表现。
再来看看co_max,即rm_max/std_max因子的逻辑。
rm_max刻画了个股与市场趋势的一致性,因子值越大,说明个股是在市场表现较好时同步出现价格上涨,与全市场上涨趋势一致,个股与市场形成有效共振,股价上涨被普遍认可,更容易延续,未来收益表现较好;std_max刻画了市场整本收益的分歧度,分歧度越小,市场趋势更具市场代表性,个胶与市场共振越有效,将其叠加后有助于提升rm_max的表现。

因子评价

从相关性来看,co_min和co_max的相关性挺高的,而co_min_resi和co_max_resi两者之间的相关性也超过了0.8。
co_min和co_max的IC表现基本一致,但是分层回测看起来co_min更舒服一点,co_min_resi和co_max_resi也是这样的。
因此,在因子评价的时候将以co_min为主,而co_min_resi仅展示分层回测结果。
01
IC分析






这个IC的表现有点平庸了,虽然它在2023年的IC绝对值超过了0.08,但是2018年的IC和其他年份方向相反了。
02
回归分析


03
换手率分析


04
收益分析


这个分层回测的表现也很一般了,区分度基本上没有。
不过,co_min_resi这个因子,其分层回测中,因子值最大的一组和其他四组之间还是有一点儿区分度的。



总结
很遗憾,这个因子无论是分层回测还是IC上的表现都不如同研报的另外一个因子,领先成交额异动。
虽然,这个因子的表现不咋地,但是笔者还是选择将其写了出来。可能有的大佬不感兴趣,但是笔者觉得排查一个效果不那么好的因子也是有价值的。
不知道各位大佬是不是也是这么想的,如果是的话,能否用点赞推荐关注和分享的方式来支持支持笔者呢?

- END -
