❌【研报复现】开源证券:日内极端收益前后的反转特性与因子构建
原始因子构建思路
原文链接:日内极端收益前后的反转特性与因子构建 | 开源金工
1. 日内最极端收益的alpha信息
本篇报告我们尝试从分钟数据出发,探寻日内极端收益前后的反转特性差异。
对于极端收益的定义,我们使用
S
=
∣
x
−
m
e
d
i
a
n
(
x
)
∣
S=|x-median(x)|
S=∣x−median(x)∣为衡量标准。
首先,从简出发,我们先考察 S S S最大的那根最极端收益bar的alpha信息。在2014/01/01-2022/09/30期间,以全体A股为研究样本(剔除ST、停牌以及上市不足60个交易日的次新股),每月底回看过去20天,计算每天S最高那根bar的收益率,并将20天进行平均作为月末调仓的因子,市值行业中性化后测算其选股能力,从十分组多空效果中可看到:虽然相比于传统反转因子,最极端收益因子多空年化收益略有降低,从21.71%降至19.10%,但信息比率从1.55提升至2.73,胜率从65.71%提升至81.90%,最大回撤从13.77%降至5.71%,是较为有效的改进方案。
进一步地,最极端收益的出现是否会对相邻时段的收益率预测方向以及能力有所影响?为了找到这一答案,我们采取如下方案进行验证:每月底回看过去20天,计算每天S最高那根bar前30分钟以及后30分钟内单根bar收益率,并针对于每根bar收益率进行20天平均作为月末调仓因子,观察由此得到的ICIR可以看出,在S最高那根bar之前和之后呈现明显不同的选股效应,具体为:
- 最极端收益前呈现反转特性。
- 我们认为具有强反转的最极端收益的出现打破了弱反转现象,而且从弱反转至强反转会存在一定渐变过程。
- 所以最极端收益前的分钟收益率整体呈现负IC,且离最极端收益率那根bar越近反转效应越强。
- 最极端收益后呈现动量特性。
- 我们认为从相关性的传导可以解释这一现象。
- 在这里我们统计了最极端收益前和后的单根bar收益率与最极端收益率的相关性,从统计结果可以看出:
- 最极端收益前的收益率与最极端收益率呈现正相关,且离最极端收益率越近正相关性越高;
- 最极端收益后的收益率与最极端收益率呈现负相关,且离最极端收益率越近负相关性越高。
结合上述结果,最极端收益后的动量现象可以被解释为:最极端收益以及之前的分钟收益率与下月收益率为负相关,而且和最极端收益之后分钟收益率也呈现负相关,所以最极端收益率后分钟收益率普遍呈现正IC。
对于最极端收益因子而言,我们可以进一步进行改进:即把最极端收益率前1分钟的收益率信息也利用进来。但是考虑到二者可能存在量级的差别,结合方式并不是数值相加,而是使用排序相加。
根据合成后的因子十分组多空对冲净值可以发现:相比于最极端收益,把前1分钟收益率也考虑进来效果有一定提升,年化收益率从19.10%提升至19.58%,信息比例从2.73提升至3.01。(后续会对极端收益率前纳入的分钟数做敏感性分析,敏感性不高)
2. 日内第N极端收益的alpha信息
接下来我们将最极端这一标准放开,考虑第N极端的alpha信息,其中第N极端收益因子的计算方式为:每月底回看过去20天,计算每天第N极端收益率,并将20天进行平均。
进一步我们对参数N进行遍历,我们发现第N极端收益因子选股ICIR随N增加基本呈现递减规律,而且在N大于10之后ICIR绝对幅度就在1.5以下。
在第一部分的分析中,我们发现最极端收益率前1分钟也具备一定alpha信息。进一步,对于第N极端收益率,我们也将其前1分钟采用排序合成给包括进去,从而发现结合各自前1分钟收益率之后,所有的单根第N极端收益的选股ICIR效果都得到了提升,而且也是基本呈现单调递减的规律。
最后我们将前N(极端收益率+前1分钟)进行排序合成,可以看出:最极端收益+前1分钟收益的因子效果是最好的。因此,在本篇报告中,我们定义“最极端收益+前1分钟收益”为极端收益率反转因子(Extreme Return Reversal Factor,简称ERR因子)。
代码实现
def factor(df, window = 96):
"""
计算极端收益率反转因子(ERR因子)
步骤:
1. 计算每根K线的收益率
2. 按自然日分组,找出每日最极端收益的K线
3. 计算最极端收益及其前一根K线的收益率
4. 计算过去20天最极端收益和前一根收益的平均值
5. 将两个平均值排序后相加得到最终因子值
"""
# 1. 计算每根K线的收益率
df = df.copy()
df['return'] = (df['close'] - df['open']) / df['open']
# 2. 按自然日分组
df['date'] = df.index.date
daily_groups = df.groupby('date')
# 存储每日的最极端收益率及其前一根收益率
extreme_data = []
for date, group in daily_groups:
if len(group) < 2: # 至少需要2根K线才能计算前一根
continue
# 计算每日收益率的中位数
median_return = group['return'].median()
# 计算每个收益率的偏离度 S = |x - median|
s_values = (group['return'] - median_return).abs()
# 找到最极端收益的K线(最大S值)
idx_extreme = s_values.idxmax()
extreme_row = group.loc[idx_extreme]
# 获取前一根K线的索引
prev_idx = group.index[group.index.get_loc(idx_extreme) - 1]
prev_row = df.loc[prev_idx]
# 存储数据
extreme_data.append({
'date': date,
'extreme_return': extreme_row['return'],
'prev_return': prev_row['return']
})
# 创建DataFrame
extreme_df = pd.DataFrame(extreme_data)
extreme_df['date'] = pd.to_datetime(extreme_df['date'])
extreme_df.set_index('date', inplace=True)
# 计算过去20天的平均极端收益率和前一根收益率
extreme_df['mean_extreme'] = extreme_df['extreme_return'].rolling(window).mean()
extreme_df['mean_prev'] = extreme_df['prev_return'].rolling(window).mean()
# 排序相加(使用排序值代替原始值)
extreme_df['rank_extreme'] = extreme_df['mean_extreme'].rank(pct=True)
extreme_df['rank_prev'] = extreme_df['mean_prev'].rank(pct=True)
extreme_df['err_factor'] = extreme_df['rank_extreme'] + extreme_df['rank_prev']
# 将因子值映射回原始DataFrame
df = df.reset_index()
df['date'] = pd.to_datetime(df['open_time'].dt.date)
df = pd.merge(df, extreme_df[['err_factor']], left_on='date', right_index=True, how='left')
df.set_index('open_time', inplace=True)
# 向前填充因子值(每月最后一天计算的值用于下个月)
df['err_factor'] = df['err_factor'].fillna(method='ffill')
return df['err_factor']
因子表现
📊 单币种 (single) 详细评估结果:
--------------------------------------------------
🔗 相关性分析:
IC (Pearson): 0.018550
Rank_IC (Spearman): 0.011474
📊 信息比率:
IR: -0.224911
评价
有点恐怖。。不会是在近期失效了吧😰😰😰