×

价变共振,同研报的另一个因子分层炸裂,它会更好吗?

wang wang 发表于2026-07-18 23:42:07 浏览3 评论0

抢沙发发表评论

价变共振,同研报的另一个因子分层炸裂,它会更好吗?

价变共振

本文,笔者将复现一下招商证券任曈老师的研报《“青出于蓝”系列研究之九-基于分钟数据的价变共振因子》。

在此之前,笔者复现了这篇研报中的领先成交额异动因子,这个因子在分层回测上的表现非常不错。

于是,让笔者对同研报中的另外一个因子也充满了兴趣。

计算步骤和代码

先来看看这个因子的计算步骤和代码,然后看看《因子日历》中对这个因子的说明。

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 / 4847 / 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(-11) * 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(-11) * 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(-11) * np.where(flag, 1.0, np.nan), axis=0)        resi_sigma = np.nanmean(mkt_sigma.values.reshape(-11) * 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_time    return 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 -