股票高频特征构建与分析03

用户头像神盾局量子研究部
2023-07-19 发布

股票高频特征构建与分析03

今天我们以一个基于股票分钟级数据构建的特征为例,以未来5分钟收益率为目标,通过构建多空组合,以及对特征进行分层计算收益率,来考察该特征的预测能力。

特征数据

本文还是以上证50的50只成分股数据为例进行,首先将逐笔快照数据合成成分钟数据,用过去的5分钟量价数据构建特征。构建特征的过程需要特别注意,要避免用到未来的数据,这一点是很多新手不经意间常犯的错误,所以要仔细检查核对。

将50只股票的特征(feature)和预测目标(label)转成相同规格的Dataframe,行列都一一对应。下面是标准化以后的特征和目标数据样本:

bc5a23104e4f715ce723ba8167531216.png

7b845d55815ca6686aadd2fbe00979b5.png

数据的时间轴是1分钟间隔,但我们的目标是未来5分钟收益率,我们把每1分钟当成一个独立事件,全天240分钟构成一个样本集。

相关性分析

在每1分钟,计算50只股票的特征值与预测目标之间的相关系数,就得到240个相关系数样本,绘制直方图如下:

c376db9c0bc1cd17ef4dbacce4e933eb.png

很直观的看到相关系数的分布整体是在负值区间,平均值是在-0.2左右,说明这个特征和未来收益率呈现负相关关系。

特征多空对冲分析

用特征值排序后将成分股分成2部分,做多特征值小的一半,做空大的一半,以对应的未来5分钟收益率的均值分别作为多、空收益率,多+空为LS收益率。这里要注意以下几点:

  1. 这里将每1分钟作为独立事件,以未来5分钟收益率为持有收益率计算,主要为了考察特征的预测能力,并不是形成的交易策略,这里要做个区分。
  2. 我们将空头收益率加了负号,相当于做空这部分股票,当然这在实际上做不到,这里也是为了考察特征。
  3. 每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

最终得到的多空对冲收益率绘图如下

1aed51297c73e5c3c26faa73b8b489f4.png

蓝色曲线是多头+空头的收益率,可以看到是向上稳定增长的,说明这个特征的多空区分效应比较显著。绿线是空头收益率,这一天的多空收益大部分来源于空头,多头(橙色)收益略战胜基准(红色,这里基准是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.)

368c0d73ad90fd46007bcab4ef7b95ad.png

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

评论