• 7
いいね
• 3
コメント
に更新
8

# 前置き

ばかちんなので動かしてみないとわかりまてん。

# 参考

Artiﬁcial neural networks approach to the forecast of stock marketprice movements

# 環境

Windows10
Python 3.5.2
keras2.0 + TensorFlow1.3
jupyter

# 次のcloseを予測してみる

## CSV読むところから

```from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from sklearn.preprocessing import MinMaxScaler
from keras.layers.core import Flatten
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

PAIR = 'USD_JPY'
TIME_SPAN = 'D'
TIME_SERIES = 5

def createRow():
row = pd.read_csv("./data/" + TIME_SPAN + "/" + PAIR + ".csv")
row.time = pd.to_datetime(row.time)
row = row.set_index('time')
row = row.iloc[:1000]
row = row.iloc[::-1]
row = row.drop(labels=['open','high','low','volume'], axis=1)
row["move0"] = row.close - row.close.shift()
row = row.iloc[1:]

scaler = MinMaxScaler(feature_range=(-1, 1))
scaler = scaler.fit(row["move0"].values.reshape(-1, 1))
row["move0"] = scaler.transform(row["move0"].values.reshape(-1, 1))
return row,scaler
```

CSV取得部分

```row["move0"] = row.close - row.close.shift()
```

ここで単純に引き算しどれだけ値が動いたかにしています。

```scaler = MinMaxScaler(feature_range=(-1, 1))
scaler = scaler.fit(row["move0"].values.reshape(-1, 1))
row["move0"] = scaler.transform(row["move0"].values.reshape(-1, 1))
```

activationをtanh(hyperbolic tangent)で行うので-1~1の間に収まるよう標準化します。

```def crateData():
row,scaler = createRow()
train_size = int(len(row) * 0.90)+TIME_SERIES
for i in range(1,TIME_SERIES):
row["move"+str(i)] = row.move0.shift(i)
row = row.iloc[TIME_SERIES:]
x = pd.DataFrame()
for i in range(TIME_SERIES):
x["move"+str(i)] = row["move"+str(i)]
y = pd.DataFrame()
row["next_close"] = row.close.shift(-1)
y = y.iloc[:-1]
x = x.iloc[:-1]
row = row.iloc[:-1]
return row, x[:train_size], y[:train_size], x[train_size:], y[train_size:],  train_size,scaler
row, x, y, x_test, y_test, train_size,scaler = crateData()
print(row.tail(10))
row['close'].plot()
plt.show()
```

10%をテストデータにして分けています。
xが特徴でTIME_SERIES(5)個前までの値段の変動になります。
yが答えで次の値段の変動をいれています。

time close move0 move1 move2 move3 move4 answer next_close
2017-08-30 06:00:00 110.2455 0.259903 0.263574 0.095107 0.063475 0.266963 0.045259 109.9745
2017-08-31 06:00:00 109.9745 0.045259 0.259903 0.263574 0.095107 0.063475 0.201299 110.2560
2017-09-01 06:00:00 110.2560 0.201299 0.045259 0.259903 0.263574 0.095107 -0.029584 109.7200
2017-09-04 06:00:00 109.7200 -0.029584 0.201299 0.045259 0.259903 0.263574 -0.134364 108.8130
2017-09-05 06:00:00 108.8130 -0.134364 -0.029584 0.201299 0.045259 0.259903 0.236885 109.2205
2017-09-06 06:00:00 109.2205 0.236885 -0.134364 -0.029584 0.201299 0.045259 -0.094683 108.4540
2017-09-07 06:00:00 108.4540 -0.094683 0.236885 -0.134364 -0.029584 0.201299 -0.050201 107.8450
2017-09-08 06:00:00 107.8450 -0.050201 -0.094683 0.236885 -0.134364 0.029584 0.559980 109.3965
2017-09-11 06:00:00 109.3965 0.559980 -0.050201 -0.094683 0.236885 0.134364 0.339688 110.1680
2017-09-12 06:00:00 110.1680 0.339688 0.559980 -0.050201 -0.094683 0.236885 0.212031 110.4875

```row['move0'].plot()
plt.show()
row['move0'].describe()
```

```count    993.000000
mean       0.124792
std        0.189740
min       -1.000000
25%        0.030008
50%        0.128010
75%        0.223752
max        1.000000
```

move0はこんな感じ。値下がったときのスパイクが大きくて平均が0になってないけどよいんかな。

## modelをつくろう

とりあえず簡単な多層パーセプトロン(MLP)を使う。
CNN,RNN(LSTM)は画像と同じぐらいデータが複雑になったら試すことにする。

```def mlp():
model = Sequential()
model.compile(
loss='mse',
return model
model = mlp()
```

## 機械学習

さあ30000回(多すぎ)学習してください。

```history = model.fit(
x.values.reshape(x.shape[0], x.shape[1]),
y.values.reshape(y.shape[0], y.shape[1]),
batch_size=32,
epochs=30000,
verbose=2,
shuffle=False)
```

verbose=2でlossだけ出るようになります。

```Epoch 1/30000
1s - loss: 0.0462
Epoch 2/30000
0s - loss: 0.0422
Epoch 3/30000
0s - loss: 0.0428
・
・
・
Epoch 29998/30000
0s - loss: 0.0212
Epoch 29999/30000
0s - loss: 0.0205
Epoch 30000/30000
0s - loss: 0.0212
```

## 結果

どんなあんばい？

```plt.plot(history.history['loss'][25:])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
```

テストデータでもmseのlossの計算をやってみる。

```score = model.evaluate(
x_test.values.reshape(x_test.shape[0], x_test.shape[1]),
y_test.values.reshape(y_test.shape[0], y_test.shape[1]))
print('Test score:', score)
```

32/89 [=========>....................] - ETA: 0s
Test score: 0.0332293912266
0.033になった。

```from sklearn.metrics import mean_squared_error
from math import sqrt
output = model.predict(x_test.values.reshape(x_test.shape[0], x_test.shape[1]))
plt.figure(figsize=(12, 6), dpi=72)
plt.plot(y_test.values, color='blue')
plt.plot(output[:,0], color='red')
plt.show()
```

```plt.figure(figsize=(12, 6), dpi=72)
plt.plot(y_test.values[:20], color='blue')
plt.plot(output[:,0][:20], color='red')
plt.show()
```

スパイクのおかげで上にずれちゃってわかりにくいや。

```ma_diff= pd.Series(output[:,0] - y_test.values[:,0])
plt.figure(figsize=(12, 6), dpi=72)
plt.plot(ma_diff, color='red')
plt.plot(np.full((len(ma_diff)),ma_diff.mean()), color='blue')
plt.show()
```

なんとなくトレンドも見えるがわかりにくい。

```import math
def invertMA(row,yhat,row_index,scaler):
yhat = scaler.inverse_transform([[yhat]])
yhat = yhat[0,0]
yhat += row["close"].iloc[row_index]
return yhat
predictions = list()
up_down = 0
for i in range(len(output)):
yhat = output[i,0]
row_index = train_size+i
yhat = invertMA(row,yhat,row_index,scaler)

real = row.next_close.iloc[row_index] - row.close.iloc[row_index]
predict = yhat - row.close.iloc[row_index]
if predict >= 0 and real >= 0 :
up_down += 1
elif predict < 0 and real < 0 :
up_down += 1
predictions.append(yhat)

print('up down predict %d/%d=%f   ' % (up_down,len(output),(up_down/len(output))))
```

up down predict 55/89=0.617978

グラフでも比較

```plt.figure(figsize=(18, 9), dpi=72)
plt.plot(row["next_close"].iloc[train_size:].values, color='blue')
plt.plot(predictions, color='red')
plt.show()
```

# まとめ

かなり施行して61%の確立で上がるか下がるかを予測するものになりました。

MLPでさくっとかましても74%ぐらいで移動平均の上下の予測ができました。