LoginSignup
1
3

More than 3 years have passed since last update.

QoreSDKを使ってBTCの価格上昇・下降を予測してみる

Last updated at Posted at 2019-12-21

だいぶ投稿が遅くなってしまいましたがこちらの記事は深層学習以外の機械学習と応用技術 by QuantumCore Advent Calendar 2019の7日目の記事です。

はじめに

Qiita - QoreSDKの紹介とQoreで不整脈検出

まずはじめにこちらのQoreSDKの紹介記事読んで、Qoreの強みが時系列データに強く、学習が高速でデータが少なくても精度が出せるという点であるということを理解しました。
そこで通貨取引の価格上昇下降のタイミングが素早く検出できれば取引の利益を大きく損失を小さくすることができるのではないかと考えました。
次に扱う題材ですがBTC(ビットコン)に決めました。また、BTCの取引履歴はオープンデータとして公開されているため開発者が扱いやすいという利点も選択理由の一つです。

というわけでKaggleに公開されていますこちらのデータをKaggleDataset - bitcoin-historical-dataを今回は使います。

これ以降の紹介で使っておりますソースコードは下記GooglaColabratoryで動作確認したコードになります。
GoogleColabratory - btc.ipynb

データの読み込み

まずKaggleDatasetからデータをダウンロードしたことを前提に話を進めます。GoogleColabratory上でKaggleDatasetからデータをダウンロードする方法については下記記事を参考にしました。

Qiita - Google Colab上でKaggleのデータをロード、モデル訓練、提出の全てを行う

まずはデータを読み込む部分です、元々加工済みのCSVファイルということもありpandasでそのまま読み込めます。

load_data.py
import numpy as np
import pandas as pd

btc = pd.read_csv("/content/bitstampUSD_1-min_data_2012-01-01_to_2019-08-12.csv")
btc.head()

"""
    Timestamp   Open    High    Low Close   Volume_(BTC)    Volume_(Currency)   Weighted_Price
0   1325317920  4.39    4.39    4.39    4.39    0.455581    2.0 4.39
1   1325317980  NaN NaN NaN NaN NaN NaN NaN
2   1325318040  NaN NaN NaN NaN NaN NaN NaN
3   1325318100  NaN NaN NaN NaN NaN NaN NaN
4   1325318160  NaN NaN NaN NaN NaN NaN NaN
"""

データの前処理

データを見てみると欠損値が存在するため、直前の値で欠損値を埋めるffillを使って欠損値を埋めます。

また今回の予測対象である価格上昇・下降の定義ですが、終値(カラムではClose)が始値(カラムではOpen)よりも値が上回っていた場合は価格が上昇したと定義します。

最後にTimestampカラムをto_datetimeを使って扱いやすいように型変換しておきます。

preprocess.py
btc[btc.columns.values] = btc[btc.columns.values].ffill()

btc['Delta'] = btc['Close'] - btc['Open']

def digitize(n):
    if n > 0:
        return 1
    return 0

btc['label'] = btc['Delta'].apply(lambda d: digitize(d))

# https://stackoverflow.com/questions/19231871/convert-unix-time-to-readable-date-in-pandas-dataframe
btc["Timestamp"] = pd.to_datetime(btc["Timestamp"], unit='s')

btc.head()
"""
Timestamp   Open    High    Low Close   Volume_(BTC)    Volume_(Currency)   Weighted_Price  Delta   label
0   2011-12-31 07:52:00 4.39    4.39    4.39    4.39    0.455581    2.0 4.39    0.0 0
1   2011-12-31 07:53:00 4.39    4.39    4.39    4.39    0.455581    2.0 4.39    0.0 0
2   2011-12-31 07:54:00 4.39    4.39    4.39    4.39    0.455581    2.0 4.39    0.0 0
3   2011-12-31 07:55:00 4.39    4.39    4.39    4.39    0.455581    2.0 4.39    0.0 0
4   2011-12-31 07:56:00 4.39    4.39    4.39    4.39    0.455581    2.0 4.39    0.0 0
"""

btc.tail()
"""
Timestamp   Open    High    Low Close   Volume_(BTC)    Volume_(Currency)   Weighted_Price  Delta   label
3997692 2019-08-11 23:56:00 11555.57    11555.57    11540.37    11540.58    0.036868    425.909106  11552.336234    -14.99  0
3997693 2019-08-11 23:57:00 11553.49    11556.22    11553.49    11556.22    0.623462    7204.428272 11555.520505    2.73    1
3997694 2019-08-11 23:58:00 11559.73    11561.22    11546.77    11561.22    0.159070    1838.731403 11559.252199    1.49    1
3997695 2019-08-11 23:59:00 11559.73    11589.73    11528.73    11528.73    16.198210   187504.635170   11575.638889    -31.00  0
3997696 2019-08-12 00:00:00 11527.44    11551.57    11520.00    11520.00    23.805939   274731.256920   11540.450291    -7.44   0
"""

モデルの学習に使う訓練データと評価に使うテストデータを作っていきます。

データを作る際の注意点としてQoreSDKの使い方について事前にメールにて以下のように注意書きがあったためそれに従うため、訓練・テストデータ共に時間長を約12時間(1サンプル1分間隔)に抑えています。

なお、一度にAPIに投げられるデータサイズに制限がありまして、N*T*V < 150,000 && N*T < 10,000の大きさまでのデータとして頂きますようお願いいたします。

またAPIのドキュメントを読むと訓練、予測時共に型がnumpy.ndarrayでありかつ学習・推論用データの次元が(データ数, 時間, 実データ)、正解ラベルの次元が(データ数, 1)であったのでそのように変換しておきます。

preprocess2.py
data = btc[('2019-01-01' < btc['Timestamp']) & (btc['Timestamp'] < '2019-01-01 12:00')]

data
"""
Timestamp   Open    High    Low Close   Volume_(BTC)    Volume_(Currency)   Weighted_Price  Delta   label
3676577 2019-01-01 00:01:00 3694.72 3694.72 3690.65 3690.65 9.500151    35080.265871    3692.600865 -4.07   0
3676578 2019-01-01 00:02:00 3689.73 3689.73 3686.62 3686.62 0.965966    3562.371230 3687.884698 -3.11   0
3676579 2019-01-01 00:03:00 3692.85 3692.85 3688.32 3692.35 0.296662    1095.220713 3691.813285 -0.50   0
3676580 2019-01-01 00:04:00 3692.35 3692.35 3690.34 3690.34 0.111622    412.065433  3691.614849 -2.01   0
3676581 2019-01-01 00:05:00 3690.40 3690.85 3690.40 3690.85 2.247676    8295.406915 3690.659723 0.45    1
... ... ... ... ... ... ... ... ... ... ...
3677291 2019-01-01 11:55:00 3706.01 3706.01 3706.01 3706.01 0.412970    1530.471061 3706.010000 0.00    0
3677292 2019-01-01 11:56:00 3706.01 3706.01 3706.01 3706.01 0.412970    1530.471061 3706.010000 0.00    0
3677293 2019-01-01 11:57:00 3706.01 3706.01 3706.01 3706.01 0.412970    1530.471061 3706.010000 0.00    0
3677294 2019-01-01 11:58:00 3706.01 3706.01 3706.01 3706.01 0.071164    263.734496  3706.010000 0.00    0
3677295 2019-01-01 11:59:00 3706.01 3706.01 3700.00 3700.00 14.862874   55009.746820    3701.151476 -6.01   0
"""

labels = data["label"]
data.drop(columns=["Timestamp", "label", "Delta"], inplace=True)
data = np.array(data)
labels = np.array(labels)

data = data.reshape((data.shape[0], data.shape[1], 1))
labels = labels.reshape((labels.shape[0], 1))

test_data = btc[('2019-01-01 12:00' < btc['Timestamp']) & (btc['Timestamp'] < '2019-01-01 23:59')]

test_data
"""
Timestamp   Open    High    Low Close   Volume_(BTC)    Volume_(Currency)   Weighted_Price  Delta   label
3677297 2019-01-01 12:01:00 3694.63 3694.63 3694.63 3694.63 2.572921    9505.991188 3694.630000 0.00    0
3677298 2019-01-01 12:02:00 3694.63 3694.63 3694.63 3694.63 2.572921    9505.991188 3694.630000 0.00    0
3677299 2019-01-01 12:03:00 3694.63 3694.63 3694.63 3694.63 2.572921    9505.991188 3694.630000 0.00    0
3677300 2019-01-01 12:04:00 3701.03 3704.20 3701.03 3704.20 2.176152    8060.808805 3704.156299 3.17    1
3677301 2019-01-01 12:05:00 3704.20 3704.20 3704.20 3704.20 0.045025    166.779901  3704.200000 0.00    0
... ... ... ... ... ... ... ... ... ... ...
3678010 2019-01-01 23:54:00 3812.78 3821.38 3812.78 3821.38 21.387205   81679.855061    3819.099098 8.60    1
3678011 2019-01-01 23:55:00 3819.70 3819.70 3816.41 3816.41 1.699109    6488.410322 3818.713657 -3.29   0
3678012 2019-01-01 23:56:00 3816.41 3816.99 3813.81 3816.99 3.007816    11480.373641    3816.847055 0.58    1
3678013 2019-01-01 23:57:00 3816.41 3816.99 3813.81 3816.99 3.007816    11480.373641    3816.847055 0.58    1
3678014 2019-01-01 23:58:00 3816.41 3816.99 3813.81 3816.99 3.007816    11480.373641    3816.847055 0.58    1
"""

test_labels = test_data["label"]
test_data.drop(columns=["Timestamp", "label", "Delta"], inplace=True)
test_data = np.array(test_data)
test_labels = np.array(test_labels)

test_data = test_data.reshape((test_data.shape[0], test_data.shape[1], 1))
test_labels = test_labels.reshape((test_labels.shape[0], 1))

モデルの学習

準備した訓練データを使ってモデルの学習をしてゆきます。今回は分類問題なので評価結果をsklearn.metrics.classification_reportを使って求めます。
今回予測したかった価格の上昇がうまく学習できていないのかまったく予測できていません。

train.py
from qore_sdk.client import WebQoreClient

# api_keyの読み取り
with open(api_key_path, "r") as f:
    api_key = json.load(f)

client = WebQoreClient(**api_key)
client.classifier_train(data, labels)
# {'res': 'ok', 'train_time': 0.8283402919769287}

response = client.classifier_predict(data)

from sklearn.metrics import classification_report

report = classification_report(labels, response['Y'])
print(report)
"""
precision    recall  f1-score   support

           0       0.66      1.00      0.79       473
           1       0.00      0.00      0.00       246

    accuracy                           0.66       719
   macro avg       0.33      0.50      0.40       719
weighted avg       0.43      0.66      0.52       719
"""

モデルのテスト

最後に訓練データにはない未知データを使って予測してゆきます。
不思議なことに学習では一切予測が当たらなかった価格の上昇をそれなりに当てています。

predict.py
response = client.classifier_predict(test_data)
report = classification_report(test_labels, response['Y'])
print(report)
"""
precision    recall  f1-score   support

           0       0.11      0.02      0.03       441
           1       0.34      0.79      0.47       277

    accuracy                           0.32       718
   macro avg       0.22      0.41      0.25       718
weighted avg       0.20      0.32      0.20       718
"""

参考

1
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
3