見出し画像

教師あり機械学習を使ってBTC価格を予想してみる②

こんにちはalumiです。第2回です。前回はこちら

前回のあらすじ
30分足のOHLCVのデータそのまま使ってロジスティック回帰したけどコイントスと同じ精度しか出せなかったよ!


※追記 後から気付きましたが、このコードで行われるスケーリングは厳密には下の説明のような変換ではありませんでした。③で補足説明しています。

今回は予告通りまずはデータの形を見直していきます。前回はOHLCVをそのまま格納したわけですが、今回は過去のローソク足の形の法則性に注目していくことにしましょう。MinMaxScalerを使っていきます。イメージはロウソク足の束を同じ大きさの箱にぴったり入るように縮めたり伸ばしたりする感じです。

こうすることで値動きの形でクラスわけしやすくなるのでは?って発想です。やっていきましょう。ボラティリティに関しては今回ちょっとデータから除外してOHLCのみ使うことにします。
また、使う過去データの本数も前回は5本としていましたが、5~30まで5本刻みで変えて試してみます。それぞれのkに対し10回ずつテストを行い、その平均と標準偏差を出力としてプロットします。そんなこんなで以下のコードができました。動かしてみます。

# coding: UTF-8

import requests

period = 1800 # 時間足(秒単位)
response = requests.get("https://api.cryptowat.ch/markets/bitflyer/btcfxjpy/ohlc",params = { "periods" : period ,"after" : 1})
response = response.json()

import numpy as np
mean = []
std = []
k_range = [5,10,15,20,25,30] # kの値の候補
for k in k_range:
    x_data = []
    y_data = []
    for i in range(6000-k-1):
        # xの要素
        arr = np.array(response['result'][str(period)][i:i+k])
        x_data.append(arr[:,1:5].ravel())
        # yの要素
        if response['result'][str(period)][i+k+1][4] - response['result'][str(period)][i+k+1][1] > 0:
            target = 1
        else:
            target = 0
        y_data.append(target)
    x = np.array(x_data)
    y = np.array(y_data)

    # 識別器の選択
    from sklearn import linear_model
    clf = linear_model.LogisticRegression()

    # 層化してシャッフル
    from sklearn.model_selection import StratifiedShuffleSplit
    ss = StratifiedShuffleSplit(n_splits = 10, train_size = 0.5, test_size = 0.5)

    # ひとつのkに対して10回繰り返して平均と標準偏差を出す
    score = []
    for train_index, test_index in ss.split(x,y):
        x_train,x_test = x[train_index],x[test_index]
        y_train,y_test = y[train_index],y[test_index]

        # スケーリング
        from sklearn.preprocessing import MinMaxScaler
        sc = MinMaxScaler([-1,1])
        sc.fit(x_train)
        x_train_scaled = sc.transform(x_train)
        x_test_scaled = sc.transform(x_test)

        clf.fit(x_train_scaled,y_train)
        score.append(clf.score(x_test_scaled,y_test))
    mean.append(np.array(score).mean())
    std.append(np.array(score).std())

# グラフを描画
import matplotlib.pyplot as plt
plt.plot(k_range,mean)
plt.xlabel("k")
plt.ylabel("score")
plt.errorbar(k_range,mean,yerr=std)
plt.show()

結果はこんな感じでした。

kが大きくなるほど認識率は下がってますね。情報量が多くなるほどクラス分けが難しいということでしょうか。そして残念ながら未だにコイントスの域を超えたものではありません。
念のため他の時間足も調べましたが、どれも0.51付近に集まっていました。kが大きくなるほど認識率が下がるのは30分足に特有のことで、他はkの値は認識率にほぼ関係していないように見えました。
まだめげません。スケーリングをせずに同じように計算させてみましょう。スケーリングしたときよりこの結果が悪ければスケーリングにはわずかですが意味があったことになります。

お、これはほんのわずかですが認識率は上がってるんじゃないでしょうか!ほんとに誤差みたいなものですけど、30分足ではすこーしだけ認識率がよくなったと言っても良さそうです。次から基本的に価格に対してMinMaxScalerを使っていくようにします。

はい、今回はここで切ります。最終的に0.65くらいの認識率が出せることを目標にしていきたいですが、先が見えないですね・・・。
次はどうしましょうか。正解ラベルを次の足1本だけの上下ではなく3本分の上下にしてみるとか、もっと要素数を増やしてみるとか、を考えています。次元が増えればPCAとかも試せると思いますし。
そんな感じでのんびり頑張ります。それではまた次回!

第3回はこちら



この記事が気に入ったらサポートをしてみませんか?