股票高频特征构建与分析03
今天我们以一个基于股票分钟级数据构建的特征为例,以未来5分钟收益率为目标,通过构建多空组合,以及对特征进行分层计算收益率,来考察该特征的预测能力。
特征数据
本文还是以上证50的50只成分股数据为例进行,首先将逐笔快照数据合成成分钟数据,用过去的5分钟量价数据构建特征。构建特征的过程需要特别注意,要避免用到未来的数据,这一点是很多新手不经意间常犯的错误,所以要仔细检查核对。
将50只股票的特征(feature)和预测目标(label)转成相同规格的Dataframe,行列都一一对应。下面是标准化以后的特征和目标数据样本:


数据的时间轴是1分钟间隔,但我们的目标是未来5分钟收益率,我们把每1分钟当成一个独立事件,全天240分钟构成一个样本集。
相关性分析
在每1分钟,计算50只股票的特征值与预测目标之间的相关系数,就得到240个相关系数样本,绘制直方图如下:

很直观的看到相关系数的分布整体是在负值区间,平均值是在-0.2左右,说明这个特征和未来收益率呈现负相关关系。
特征多空对冲分析
用特征值排序后将成分股分成2部分,做多特征值小的一半,做空大的一半,以对应的未来5分钟收益率的均值分别作为多、空收益率,多+空为LS收益率。这里要注意以下几点:
- 这里将每1分钟作为独立事件,以未来5分钟收益率为持有收益率计算,主要为了考察特征的预测能力,并不是形成的交易策略,这里要做个区分。
- 我们将空头收益率加了负号,相当于做空这部分股票,当然这在实际上做不到,这里也是为了考察特征。
- 每1分钟作为独立样本,所以没有考虑交易手续费。
1# 特征分析——多空对冲
2def analyse_feature_LS(feature_df, label_df):
3 mid = int(feature_df.shape[1] / 2)
4 s_rtn_list = []
5 for k in range(feature_df.shape[0]):
6 this_rtn = np.array(feature_df.iloc[k, :])
7 rtn_fut = np.array(label_df.iloc[k, :])
8 corr = np.corrcoef(this_rtn, rtn_fut)
9 idx = np.argsort(this_rtn)
10 idx_long = idx[:mid]
11 idx_short = idx[-mid:]
12 s_rtn_long = rtn_fut[idx_long].mean()
13 s_rtn_short = - rtn_fut[idx_short].mean()
14 s_rtn = s_rtn_long + s_rtn_short
15 s_rtn_list.append([str(feature_df.index[k]), s_rtn, s_rtn_long, s_rtn_short, rtn_fut.mean(), corr[0, 1]])
16 s_rtn_df = pd.DataFrame(s_rtn_list, columns=['time', 'rtn_ls', 'rtn_long', 'rtn_short', 'rtn_bench', 'corr'])
17 s_rtn_df.index = s_rtn_df['time']
18 return s_rtn_df
最终得到的多空对冲收益率绘图如下

蓝色曲线是多头+空头的收益率,可以看到是向上稳定增长的,说明这个特征的多空区分效应比较显著。绿线是空头收益率,这一天的多空收益大部分来源于空头,多头(橙色)收益略战胜基准(红色,这里基准是50只成分股的等权平均收益率)。
特征分层分析
接下来对特征值进行分层(10层),计算每层的预测收益率均值,观察这个特征的分层效果。实现代码如下:
1# 特征分析——分层
2def analyse_feature_layer(feature_df, label_df):
3 layer_rtn = pd.DataFrame(0., index=feature_df.index, columns=list(range(10)))
4 for k in range(feature_df.shape[0]):
5 # 分层
6 factor_df_layers = pd.cut(feature_df.iloc[k,:], 10, labels=False, duplicates='drop')
7 factor_df_layers.dropna(inplace=True)
8 if factor_df_layers is None or len(factor_df_layers) == 0:
9 continue
10 # 合并分层结果和收益率
11 merged_df = pd.concat([factor_df_layers, label_df.iloc[k,:]], axis=1)
12 merged_df.columns = ['layer', 'return']
13 avg_returns_by_layer = merged_df.groupby('layer').mean()
14 layer_rtn.iloc[k,:] = avg_returns_by_layer.iloc[:,0]
15 return layer_rtn.fillna(0.)

从特征分层结果看,效果还是不错的,尤其是layer_0(特征值最小的一组)和layer_9(特征值最大的一组),与其他组形成了较大的区分度。我们就要多寻找对未来收益率能形成区分度的特征,为后面的工作打下好的基础。

