トレンドスキャン法について
トレンドスキャン法は「アセットマネージャーのためのファイナンス機械学習 第5章: 金融データのラベリング」で紹介されているラベリング手法です。
株価等の時系列が下降トレンド、無トレンド、上昇トレンドのいずれかに応じて{-1, 0, 1}を付与したラベルを作成するというアイデアです。
def ols_t_value(close):
# 線形トレンドのt値を計算する
x = np.ones((close.shape[0], 2))
x[:, 1] = np.arange(close.shape[0])
ols = sm1.OLS(close, x).fit()
return ols.tvalues[1]
このコードは株価終値を時系列のインデックスで、OLS回帰したときのt値を求めています。(関数名など一部変更しています。)
例えばこのようなデータを用意して
import yfinance as yf
data = yf.Ticker('SPY')
spy = data.histry(period='1y')
close = spy['Close'].iloc[-20].to_numpy()
print(ols_t_value(close))
上記のように実行すると、t値が出力されます。
このコードでは20日分の終値のt値を出力していますが、期間を変えれば結果も変わります。そこで、t値の絶対値が大きくなる期間を探索するために、期間を可変するコードを考えます。
def get_bins_from_trend(molecule, close, span):
"""
線形トレンドのt値の符号からラベルを作成
入力:
- molecule: ラベル付けしたい観測値のインデックス
- close: 終値(時系列)
- span: 探索する期間の範囲[開始, 終了+1, 間隔]
出力:
- t1: 発見されたトレンドの終了時点
- t_val: 推定トレンド回帰係数のt値
- bin: トレンドの符号
"""
out = pd.DataFrame(index=molecule, columns=['t1', 't_val', 'bin'])
hrzns = range(*span)
for dt0 in molecule:
df0 = pd.Series(dtype=float)
for horizon in hrzns:
dt1 = dt0 + pd.Timedelta(days=horizon)
if dt1 > close.index[-1]:
break
df_segment = close.loc[dt0:dt1]
t_val = ols_t_value(df_segment.values)
df0.loc[dt1] = t_val
if not df0.empty:
t1 = df0.abs().idxmax()
out.loc[dt0, ['t1', 't_val', 'bin']] = [t1, df0[t1], np.sign(df0[t1])]
out['t1'] = pd.to_datetime(out['t1'])
out['bin'] = pd.to_numeric(out['bin'], downcast='signed')
return out.dropna(subset=['bin'])
※コードは変更しています。元のコードは書籍を参考にしてください。
t値の絶対値が最も高くなる期間を探索して、①探索期間、②t値、③トレンドの符号、の3つ列を含んだデータフレームを返します。このデータがルックフォワード期間の中で最も有意なトレンドを示しており、予測モデルのターゲットとなります。
先ほどyfinanceで取得したSPYのデータで試してみましょう。
close = spy['Close']
bins_df = get_bins_from_trend(close.index, close, [3,10,1])
bins_dfの中身は元データのインデックス(datetime)を維持したまま、ルックフォワードのトレンド情報が入っています。
plt.scatter(bins_df.index, close.loc[bins_df.index],
c=bins_df['bin'], cmap='viridis')
plt.colorbar()
plt.title('Trend Labelling')
plt.xlabel('Time Index')
plt.ylabel('Close')
plt.show()
これで各終値時点でのルックフォワード期間のトレンドがラベリングできました。
書籍と同様にt値も可視化してみましょう。
plt.scatter(bins_df.index, close.loc[bins_df.index],
c=bins_df['t_val'], cmap='viridis')
plt.colorbar()
plt.title('t-value')
plt.xlabel('Time Index')
plt.ylabel('Price')
plt.show()