USDJPYの動きを予測する0

やること

USDJPYの動きをランダムフォレストを用いて予測する。

サイン点灯(上がるという予測がでたら)ポジションを取り基本的に1日でクローズするという簡単な設定でまずやってみる。

参考サイト

Python scikit-learnのランダムフォレストで受診予約のNo-Showを予測する - け日記

コード

import asset_df

import numpy as np
import pandas as pd
import seaborn as sns

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import train_test_split
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import f1_score

def calc_rsi(inp: pd.Series) -> pd.Series:

    diff = inp.diff()
    up, down = diff.copy(deep = True), diff.copy(deep = True)

    up[up < 0] = 0
    down[down > 0] = 0

    up_sma_14 = up.rolling(window = 14).mean()
    down_sma_14 = down.abs().rolling(window = 14).mean()

    rs = up_sma_14 / down_sma_14
    rsi = 100. - (100. / (rs + 1.))

    rsi.name = 'RSI'
    
    return rsi

#  make DataFrame
df = asset_df.make_df() #  %
USDJPY = df['USDJPYCR']
# USDJPY.head(10)

#  make correct answer flag
y = USDJPY.apply(lambda x:1 if x > 0 else 0)
y.name = 'UpDown'

#  data in sample
ma_5 = USDJPY.rolling(window = 5).mean() #  moving average in 5 days
ma_5.name = 'MA5'

ma_20 = USDJPY.rolling(window = 20).mean() #  moving average in 20 days
ma_20.name = 'MA20'

rsi = calc_rsi(USDJPY) #  RSI(14 days)

sample = pd.concat([ma_5, ma_20, rsi], axis = 1)

#  merge data
data = pd.concat([y, sample], axis = 1)
data = data.dropna()

# data.head(5)

ma5_ = data['MA5']
ma20_ = data['MA20']

ma_diff = ma5_ - ma20_
ma_diff.name = 'MA5-MA20'

data = pd.concat([data, ma_diff], axis = 1)

#  特徴量の偏りをチェック
sns.set()
data.hist(figsize = (12,12))

#  random forest
features = data.drop('UpDown', axis = 1).values
label = data['UpDown']

X_train, X_test, y_train, y_test = train_test_split(features, label, test_size = 0.3, random_state = 1234)

clf = RandomForestClassifier(random_state = 1234)
clf.fit(X_train, y_train)

#  評価
print('Test score: {}'.format(clf.score(X_test, y_test)))
print('Train score: {}'.format(clf.score(X_train, y_train)))
print('f1 score: {:.3f}'.format(f1_score(y_test, clf.predict(X_test))))

結果

Test score: 0.7230878186968839
Train score: 0.978749241044323
f1 score: 0.719

train scoreがtest scoreよりかなり大きくなってしまい、過学習が起きていそう。これをもとに特徴量など改善していきたい。

個人的にまず気になったのが、RSI。一般的に20~30%を切ったら買い時、70~80%を超えたら売り時とされるが、ほぼ30~70%内で推移しており、予測に適しているのか疑問。次で詳しくみてみる。