Jupyterの練習にPythonでビットコインの変動を見る(1)

Share Button

ずっとMS Visual Studio Code使っててJupyter Notebookを実に中途半端にしか使ってこなかったので、データの取得や可視化を一回ちゃんと練習しておきたいと思う。もう卒業したけどビットコインのデータが一番面白そうなのでBitFlyerのデータ使って遊んでみることに。

とりあえずまず環境ごと作り直す。

pip install --upgrade pip
cd ~
virtualenv btc
cd btc
source bin/activate
pip install jupyter numpy pandas statsmodels matplotlib

BitFlyerの解析として,CRYPTOCOMPAREからデータを拝借する。
APIは
みたいな感じらしい。
1時間単位のデータで一回の取得の上限は2000件(=1回の取得で83日ぐらい)だそうですが,独特なのが,データの取得に使うtoTs=というパラメータがfromではなくtoなんですよね。つまりtoTs=1483196400(2017年1月1日 00:00:00)を指定して2000件取ってくると,前年のなんか10月の半ばぐらいからデータが始まるわけです。個人的には本当に気になってるのは2017年後半ぐらいのデータだけなんだけど、季節変動とかも見たいのでとりあえず2年分ぐらいを取得(完全な毎時データとしては2015年6月の半ばぐらいからしか返ってこなかった)。
操作ミスで欠損出たりしてもだるいしとりあえずまあ2ヶ月単位ぐらいでざっくばらんに取ってきてからunixtimeベースのタイムスタンプをキーに重複を潰す作戦でいきます。

データを取得する

まずはデータ取得から重複潰すまで。
import pandas as pd
import numpy as np
import math
import time
import datetime
import json
import requests
from matplotlib import pyplot as plt

BASE = 'https://min-api.cryptocompare.com/data/histohour?fsym=BTC&tsym=JPY&limit=2000&e=bitFlyer&toTs='

for y in [2015, 2016, 2017]:
    for m in range(6):
        if y == 2015 and 2*(m+1) < 7:
            continue
        else:
            date = datetime.datetime(y, 2*(m+1), 13, 0, 0, 0)
            print date
            date_unix = int(time.mktime(date.timetuple()))
            URL = BASE + str(date_unix)
            r = requests.get(URL)
            j = r.json()['Data']
            if not 'df' in locals():
                df = pd.DataFrame(j)
            else:
                df = df.append(pd.DataFrame(j))
df = df.drop_duplicates(['time'])

基本なんとなくやってるのでプログラマ諸氏におかれましてはイライラされるかもしれませんが。愚直な感じで書いてます。

データの加工

取ってきたデータはJSONなので、肝心な[‘Data’]だけ抽出して取ってきた順にパース、pandasのデータフレームに格納していきます。その後タイムスタンプの変数であるtimeを見て重複を削っています。

# PROCESSING THE ACQUIRED DATASET

import copy
df2 = copy.deepcopy(df)

df2 = df2.rename(columns={'time': 'unixtime'})
df2['datetime'] = df2['unixtime'].apply(lambda x: datetime.datetime.fromtimestamp(x))
df2['date'] = df2['datetime'].apply(lambda x: datetime.datetime.date(x))
df2['time'] = df2['datetime'].apply(lambda x: datetime.datetime.time(x))
df2 = df2[df2['high'] != 0]
df2['price'] = (df2['high']+df2['low'])/2
df2['logprice'] = df2['price'].apply(lambda x:math.log(x))

print df2

DataFrameで何か失敗するごとにデータ取得からやり直してるとせっかく提供してくれているサーバに負荷がかかるので、deepcopyしてから触ってます。
取得してきたunixtimeから日時(datetime), 日付(date),時間(time)を算出し直していますが、これは見やすいようにというのもありますが、あとで日次のdailyHighとdailyLowを計算させたいからでもあります。あと対数価格はあとでグラフで可視化した時に縦軸をいじった方が本当はわかりやすいけど今回は練習のために。

プロットで可視化する

次はとりあえず時系列の価格変化をプロットします。各サンプルについてhighとlowしかないので、とりあえず全値についてその中間値でpriceを作ってプロットする。そして価格上昇がきつくて見づらいので対数グラフも確認する。

# VISUALISE THEM

plt.figure(figsize=(10, 5))
plt.subplot(121)
plt.plot(df2['datetime'], df2['price'])
plt.title('JPY/BTC')
plt.xlabel('2017(unixtime)')
plt.ylabel('JPY')

plt.subplot(122)
plt.plot(df2['datetime'], df2['logprice'])
plt.title('log JPY/BTC')
plt.xlabel('2017(unixtime)')
plt.ylabel('log(JPY)')

plt.show()


うん、まあ見慣れた図が出てきただけですね。

季節変動の抽出

簡単に言うとRのdecomposeぐらいのノリで,加法モデル使って変動をトレンド・季節変動・残差にわけたい。とりあえずstatsmodelsパッケージのseasonal_decomposeでやります。

# CHECK THE SEASONAL EFFECT

from statsmodels.tsa.seasonal import seasonal_decompose
df2.index = pd.DatetimeIndex(df2['unixtime'])
original = df2['price']
decomposed = seasonal_decompose(original, model='additive', freq=24)
plt.figure(figsize=(20, 20))
decomposed.plot()
plt.show()


とりあえず時間データをいきなり突っ込む。日次データでの季節効果の分析は次回ちゃんと。
まずpandasのデータフレームのindexにDatetimeIndexを指定しています。これをやらないと変なエラーが出る。あとはもうadditiveモデルを指定して、周期の指定をするだけ。今回は時間単位なので試しに24周期にしてデイリーの効果が見られるかをチェック。


これではわからないのでx軸の範囲を絞る。日次変動は全期間で同じ動きをするので範囲は適当でいい。
plt.xlim(
    datetime.datetime(2017, 11, 21, 0, 0, 0, 0),
    datetime.datetime(2017, 12, 3, 0, 0, 0, 0)
)


毎日およそ決まった時間に1000円動いてたらトレンドなくても儲かりますわな。2015年から今まで参入者の規模感とか習熟度とか色々変わってるわけで、あの当時といまで参入している集団の行動が同じとは到底思えないし,値動きを全く同じ性質のデイリーにはめ込むのは正しくないような気がしてきますね。

直近3ヶ月のデータだけで実施

新しいDataFrameを作って範囲を絞ります。

# CHECK THE SEASONAL EFFECT (Recent)

df3 = df2[df2['datetime'] >= datetime.datetime(2017, 9, 14, 0, 0, 0, 0)]
original = df3['price']
decomposed = seasonal_decompose(original, model='additive', freq=24)
plt.figure(figsize=(20, 20))
decomposed.plot()
plt.show()


当たり前ですが,変わります。
拡大します。


日次変動のケタが変わりましたね。そら全期間で見るより直近3ヶ月で見た方がはるかに変動が大きいので当たり前ですね。しかしケタは変わっても日次周期での動きとしてはほぼ同じなので、ある意味では真理なのかもしれない。
とはいえ日次の変動なんか見てても仕方ないので,次回は日次で集計しなおして,やりたい分析をいくつか詳細にやります。

style="display:block; text-align:center;"
data-ad-layout="in-article"
data-ad-format="fluid"
data-ad-client="ca-pub-3546003055292762"
data-ad-slot="5749192034">

Share Button

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.