🗂

SIGNATE日本取引所グループ ニュース分析チャレンジ[モデル構築編3]

2021/05/01に公開

SIGNATE日本取引所グループ ニュース分析チャレンジ[モデル構築編2][1]の続き

ルール

  • 100万円を元手に月曜日にポートフォリを組み(買い)、金曜日にすべて売る
  • 途中で売り買いできない
  • 5銘柄以上 and 50万円以上の買いが必須

戦略

  • 予測対象: リターン((金曜日のclose価格 - 月曜日のopen価格) / 月曜日のopen価格)
  • 予測に基づきポートフォリを組む (とりあえずtop10の銘柄を10万円で買う)

特徴量

AAAI2021で提案された[2]spectral residualsと呼ばれる特徴量を使う.

個別株のリターンを市場全体からの要因と個別株の要因に分離し、市場全体からの要因を取り除くことで市場全体からの影響を取り除きつつリターンを狙うことができるようになる. 具体的にはPCAを行い、トップからいくつかの主成分を取り除く.

この論文は3つの要素から成り立つ。1つめは個別株のリターンをインデクスからの要因と個別株の要因に分離する方法(spectral residualsと呼ばれ、シャープレシオに効く部分を取り出す)。2つめはSpecrtral residualsから将来のSpectral residualsの分布を予測するニューラルネットワークの作り方(特にtime scaleのフラクタル性を考慮したアーキテクチャー)。3つめは、specrtral residualsの予測分布にともなったportoflioのrebalance.

Spectral residualsは端的にいうと、投資のリターンを株式の銘柄の数S\times Sの共分散行列にして、PCAをしたreturnのことである。H>1 step時間が進んだときのreturnを考える。するとリターンはX_{t}\equiv\left[\vec{r}_{t-H},\cdots,\vec{r}_{t-1}\right]\in\mathbb{R}^{S\times H}. 行ベクトルの平均を0にした\tilde{X}_{t}

\tilde{X}_{t}=X_{t}-\frac{1}{H}\sum_{i=1}^{H}X_{i}

これは特異値分解できて

\tilde{X}_{t} =V_{t}{\rm diag}\left(\sigma_{1},\cdots\sigma_{S}\right)U_{t}

ここでV_{t}は直交行列であり、H stepで得られるreturnはV_{t}^{\top}\tilde{X}_{t}={\rm diag}\left(\sigma_{1},\cdots\sigma_{S}\right)U_{t}で表現される。ここで意味を考えると、銘柄Sと時間HでのリターンをSの空間とHの空間でユニタリ変換して伸ばしたり縮めたりした感じ。つまりV_{t}は一番変化する銘柄の組み合わせ。time window Hが与えられたときに、時刻t-H\leq s\leq t-1におけるspectral residualは

\vec{\varepsilon}_{s}=V_{t}{\rm diag}\left(0,\cdots,0,1,\cdots1\right)V_{t}^{\top}\vec{r}_{s}

トップC個の固有値を0にしたときのreturnのベクトル。つまりH stepで一番変化する銘柄の組み合わせを取り除いたものをspectral residualと呼ぶ。論文中ではH=256, C=30だがメモリの関係でH=64, C=7を用いた.

def residual_feature(input_df, H = 64,  C = 7):
    assert C <= H
    tmp = input_df.loc[:, ['Local Code', 'EndOfDayQuote ExchangeOfficialClose']]
    ret_df = tmp[['Local Code']].copy()
    for diff in tqdm(range(1, H+1)):
        _df = tmp.groupby('Local Code').pct_change(diff).rename(columns={'EndOfDayQuote ExchangeOfficialClose': f'{diff}'})
        ret_df = pd.concat([ret_df, _df], axis=1)
    ret_df
    # noramalize
    # fillna = 0 新しいcodeの出現に対応するため
    norm_ret_df = pd.DataFrame(ret_df.drop('Local Code', axis=1).fillna(0).values - ret_df.drop('Local Code', axis=1).fillna(0).mean(1).values.reshape(-1,1), index=ret_df.index, columns=ret_df.columns[1:])

    norm_ret_df['Local Code'] = ret_df['Local Code']
    ret = []
    pca = sklearn.decomposition.PCA()
    for date in tqdm(norm_ret_df.reset_index()['EndOfDayQuote Date'].unique()):
        norm_ret_df = norm_ret_df
        x = norm_ret_df.loc[date].set_index('Local Code')
        x = x.fillna(0.0)
        x = x.replace([np.inf, -np.inf], 0.0)
        pca_model =  pca.fit(x)
        new_x = pca_model.transform(x)
        new_x[:, :C] = 0.0
        new_x = pca_model.inverse_transform(new_x)    
        tmp_df = pd.DataFrame(new_x, columns=x.columns, index=x.index)
        tmp_df['EndOfDayQuote Date'] = date
        ret.append(tmp_df)
    ret = pd.concat(ret, axis=0)
    ret = ret.reset_index().sort_values(['Local Code', 'EndOfDayQuote Date']).set_index('EndOfDayQuote Date')
    return ret.drop(['Local Code'], axis=1)

学習はLight gbmを使う

結果

1週間のリターンが 0.61% (あまり良くない

選択した各銘柄のリターン

予測に聞いた特徴量ベクトルの解析

特徴量ベクトルを再考

前回までの特徴量ベクトルにspectral residualsを加えてみる. せっかく市場全体からの影響を取り除いたのに、加えてるの理論的には矛盾したことをやっている.

1週間のリターンが5.57% (微妙

脚注
  1. 前記事 ↩︎

  2. Deep Portfolio Optimization via Distributional Prediction of Residual Factors
    ↩︎

Discussion