Pythonで仮想通貨を解析してみた。

## 0.  はじめに
2017年頃から一気に流行り始めて、一時bitcoinが2万ドルを付けました。2018年は6～7000ドル程度まで下がり始めているとはいえ、まだまだ根強い人気がありますね。様々な人が統計・機械学習手法を用いて解析をしていると思うけれど、私もWSL(Windows Subsystem for Linux)でちょっとやってみた。

参考サイト（引用）は下記です。<br>
<em>Analyzing Cryptocurrency Markets Using Python:<em>
https://blog.patricktriest.com/analyzing-cryptocurrencies-python/

## 1. 仮想環境構築
### 1.1 Anacondaとは
[Anaconda](https://www.anaconda.com/)はデータサイエンスのプラットフォームで最も有名。Python単独だと、必要なパッケージをインストールしなければならないが、Anacondaだと機械学習や可視化等のパッケージは標準インストールできる。

Anacondaのインストール- https://www.continuum.io/download

```sh
$ wget https://repo.anaconda.com/archive/Anaconda3-5.2.0-Linux-x86_64.sh
$ chmod u+x Anaconda3-5.2.0-Linux-x86_64.sh
$ ./Anaconda3-5.2.0-Linux-x86_64.sh
```
上記コマンドでインストール用のスクリプトを取得して実行できる。

### 1.2 構築
はじめに仮想環境を構築する。作成は`conda create`で行う。デフォルトでは、condaディレクトリの`envs`下に作成される。仮想環境を作り、アクティベートする。

```
conda create --name cryptocurrency-analysis python=3.6
source activate cryptocurrency-analysis
```

> 有効を解除するには、Linux/Macでは`source deactivate`にてできる。詳しくは、[ユーザーガイド](https://conda.io/docs/user-guide/tasks/manage-environments.html)参照

次に、環境に必要なパッケージをインストールする。

```
conda install numpy pandas nb_conda jupyter plotly quandl
```
> `numpy`は科学技術における数値処理操作に特化したパッケージ。`pandas`はデータ処理や解析に、`nb_conda`はanaconda上ではjupyter notebookを動かすために必要。`jupyter`は解析結果をブラウザ上で表示するためのノートブックとして使用する。`plotly`は可視化用。matplotlibでもよいが、時系列データの可視化はploylyやdygraphsの方がキレイだし、なにより`plotly`はHTML, CSS, JS取得できる。`qundl`は金融・経済などの数値データの検索できるAPI。これでデータを取得する。

仮想環境は、ソフトウェアのライブラリやパッケージの依存関係解いったコンフリクトを避けることができるのメリット。

仮想環境の確認は次のコマンド。

```sh
$ conda info -e
# conda environments:
#
base                  *  /home/user/anaconda3
cryptocurrency-analysis     /home/user/anaconda3/envs/cryptocurrency-analysis
```

### 1.3 Jupyter Notebook
Pythonによる実行結果をブラウザ上で表示できる。起動するためには、`jupter notebook`とするとlocalhost上でブラウザから起動できる。

```python

import os
import numpy as np
import pandas as pd
import pickle
import quandl
from datetime import datetime
```
次に、オフラインモードでPlotlyをインポートする。

```py3
import plotly.offline as py
import plotly.graph_objs as go
import plotly.figure_factory as ff
py.init_notebook_mode(connected=True)
```

## 2. Bitcoin価格の取得
データはQuandlの[Bitcoin API](https://blog.quandl.com/api-for-bitcoin-data)から取得する。

### 2.1 データを得るためのHelp関数定義
```py3
def get_quandl_data(quandl_id):
    ''' Quandlの時系列データのキャッシュを取得'''
    cache_path = '{}.pkl'.format(quandl_id).replace('/','-')
    try:
        f = open(cache_path, 'rb')
        df = pickle.load(f)   
        print('Loaded {} from cache'.format(quandl_id))
    except (OSError, IOError) as e:
        print('Downloading {} from Quandl'.format(quandl_id))
        df = quandl.get(quandl_id, returns="pandas")
        df.to_pickle(cache_path)
        print('Cached {} at {}'.format(quandl_id, cache_path))
    return df
```
APIから得られたデータをpickleでシリアライズし、ファイルとしてデータを保存する。スクリプトを実行させるたびに同じデータを再ダウンロードするのを防げる。Pandasをデータフレームとしてデータを返す。
> 下記のpickleの記事がわかりやすい。https://www.lifewithpython.com/2013/05/pickle.html

### 2.2 Kraken為替レートの取得。
[kraken](https://www.kraken.com/)からビットコインのレートを取得することできる。実際に、'BCHARTS/KARKENUSD'としてデータをシリアライズする。

```py3
btc_usd_price_kraken = get_quandl_data('BCHARTS/KRAKENUSD')

#Downloading BCHARTS/KRAKENUSD from Quandl
#Cached BCHARTS/KRAKENUSD at BCHARTS-KRAKENUSD.pkl
```
Pandasのデータフレームなので、`head()`を実行すると

```py3
In [1] : btc_use_price_kraken.head()
Out[1] :
	           Open	    High	    Low	       Close	   Volume (BTC) Volume (Currency)	Weighted Price
Date							
2014-01-07	874.67040	892.06753	810.00000	810.00000	15.622378	13151.472844	841.835522
2014-01-08	810.00000	899.84281	788.00000	824.98287	19.182756	16097.329584	839.156269
2014-01-09	825.56345	870.00000	807.42084	841.86934	 8.158335	 6784.249982	831.572913
2014-01-10	839.99000	857.34056	817.00000	857.33056	 8.024510	 6780.220188	844.938794
2014-01-11	858.20000	918.05471	857.16554	899.84105	18.748285	16698.566929	890.671709
```

データフレームとして時刻、始値、高値、安値、終値、ボリュームなど得られている。この時系列データをプロットしよう。まずは単純にx軸にはindex (Date), y軸にはWeighted Price値を指定する。

```py3
# Chart the BTC pricing data
btc_trace = go.Scatter(x=btc_usd_price_kraken.index, y=btc_usd_price_kraken['Weighted Price'])
py.iplot([btc_trace])
```

![BTC_USDplot.png](https://qiita-image-store.s3.amazonaws.com/0/230659/0d579bf9-44d8-c3fd-f0e2-2a46749c8026.png)

> 2017年付近から2018年7月までのチャート。2017年の時に買って、年末売っていれば億り人でしたね・・・

### 2.3 他の交換所のビットコインレートを取得する
上記の画像では表示させていないが、Krakenのビットコインはスパイクデータが多数あるため、他の交換所のデータもプルする。取得したデータをデータフレームのカラムに追加して、それらの平均をとっておく。

```py3
# 他の交換所のレートを取得する
exchanges = ['COINBASE', 'BITSTAMP', 'ITBIT']
exchange_data = {}
exchange_data['KRAKEN'] = btc_usd_price_kraken

for exchange in exchanges:
    exchange_code = 'BCHARTS/{}USD'.format(exchange)
    btc_exchange_df = get_quandl_data(exchange_code)
    exchange_data[exchange]=btc_exchange_df

def merge_dfs_on_column(dataframes, labels, col):
    '''データフレームへ新しいカラムを追加する'''
    series_dict = {}
    for index in range(len(dataframes)):
        series_dict[labels[index]] = dataframes[index][col]
        
    return pd.DataFrame(series_dict)

btc_usd_datasets = merge_dfs_on_column(list(exchange_data.values()), list(exchange_data.keys()), 'Weighted Price')

# 各交換所のビットコインレートの平均をとる。
btc_usd_datasets['avg_btc_price_usd']=btc_usd_datasets.mean(axis=1)
```


## 3. アルトコインの価格データを取得する
### 3.1 Poloniex API
仮想通過のデータを取ってくるために、Poloniex APIを使用する。アルトコインデータを取得のために、このAPIからJSONデータをダウンロードしキャッシュする関数を定義する。初めにURLからJSONデータを得る`get_json_data`を定義する。

```py3
def get_json_data(json_url, cache_path):
    '''Download and cache JSON data, return as a dataframe.'''
    try:        
        f = open(cache_path, 'rb')
        df = pickle.load(f)   
        print('Loaded {} from cache'.format(json_url))
    except (OSError, IOError) as e:
        print('Downloading {}'.format(json_url))
        df = pd.read_json(json_url)
        df.to_pickle(cache_path)
        print('Cached {} at {}'.format(json_url, cache_path))
    return df
```
次に、Poloniex API HTTP requestsを生成する関数を定義し、続いて、get_json_data関数を呼び出す。

```py3
base_polo_url = 'https://poloniex.com/public?command=returnChartData&currencyPair={}&start={}&end={}&period={}'
start_date = datetime.strptime('2015-01-01', '%Y-%m-%d') # get data from the start of 2015
end_date = datetime.now() # up until today
pediod = 86400 # pull daily data (86,400 seconds per day)

def get_crypto_data(poloniex_pair):
    '''Retrieve cryptocurrency data from poloniex'''
    json_url = base_polo_url.format(poloniex_pair, start_date.timestamp(), end_date.timestamp(), pediod)
    data_df = get_json_data(json_url, poloniex_pair)
    data_df = data_df.set_index('date')
    return data_df
```

### 3.2 Poloniexから取引データをダウンロードする
ほとんどのアルトコインはドルで直接購入できない。これらのコインを購入するためにはビットコイン建ての必要がある。そのため、それぞれのコインの価格はBTCを用いてUSDへと変換する。

```py3
altcoins = ['ETH','LTC','XRP','ETC','STR','DASH','SC','XMR','XEM']

def get_altcoin():
    altcoin_data = {}
    for altcoin in altcoins:
        coinpair = 'BTC_{}'.format(altcoin)
        crypto_price_df = get_crypto_data(coinpair)
        altcoin_data[altcoin] = crypto_price_df
    return(altcoin_data)
```

### 3.3 Convert Prices to USD
BTC/ALTの為替レートが得られたので、USD/BTCレートからそれぞれのアルトコインの価格が計算できる。

```math
\text{ALT/USD = ALT/BTC * BTC/USD}
```

```py3
# それぞれのアルトコインのデータフレームへ新しいカラムとしてUSDの価格を計算する
for altcoin in altcoin_data.keys():
    altcoin_data[altcoin]['price_usd'] =  altcoin_data[altcoin]['weightedAverage'] * btc_usd_datasets['avg_btc_price_usd']

# 単一のデータフレームへ統合する。
combined_df = merge_dfs_on_column(list(altcoin_data.values()), list(altcoin_data.keys()), 'price_usd')

# データフレームへBTC価格を追加
combined_df['BTC'] = btc_usd_datasets['avg_btc_price_usd']
```
### 3.4 各通貨の相関解析
ピアソンの相関係数を計算してみる。

```
combined_df_2018 = combined_df[combined_df.index.year == 2018]
combined_df_2018.pct_change().corr(method='pearson')
```

![corr.PNG](https://qiita-image-store.s3.amazonaws.com/0/230659/2cc425e7-ab6a-d33d-f82a-5c24488caeee.png)

2018年度の相関係数を見ると、ほとんど全ての通貨に相関がある。これはヘッジファンドの影響だとか。


### 3.5 散布図
散布図を見てみると次のようなる。

```python
altcoins = ['ETH','LTC','XRP','ETC','STR','DASH','SC','XMR','XEM', 'BTC']

traced = go.Splom(dimensions=[dict(label=altcoin, values=combined_df_2018[altcoin]) for altcoin in altcoins],
                  marker=dict(#color=color_vals,
                              size=5,
                              #colorscale=pl_colorscaled,
                              line=dict(width=0.5,
                                        color='rgb(230,230,230)') ),
                  #text=textd,
                  diagonal=dict(visible=True))
fig = dict(data=[traced]) #, layout=layout)
py.iplot(fig, filename='large')
```

![scatter.PNG](https://qiita-image-store.s3.amazonaws.com/0/230659/d51f1159-17e7-54d7-3d87-c2045e14faa2.png)

上記のように相関係数はほとんどが0.7以上なので、散布図を見ても相関関係があるのが一目でわかる。

## 4. Your Turn
他の方も試してみてくださいとのこと。アイデアは下記の通り。

* より仮想通貨を追加して解析してみる。

* トレンドの時間軸、粒度を変更して相関解析をしてみる。

* 取引量やブロックチェーンマイニングデータセットのトレンドを検索してみる。売/買量の比率は生データよりも将来の変動を予測したいなら関係性がある可能性が高い。

* 株やコモディティなどのデータを追加して、それらと仮想通貨の関係性をみてみる。

* Event Registry, GDELTやGoogle Trendsを利用して、特定の仮想通貨まわりのバズを量的化してみる。

* 機械学習モデルを利用して明日の価格を予測してみる。もし、より野心があるなら、再帰的ニューラルネットワーク（RNN）を試してみる。

* 例えばPoloniex or CoinbaseのAPIを使って自動化された取引Botを作るために解析を利用してみる。ただし、貧弱に最適化されたbotはお金を直ぐに減らすだけ。

* 発見を共有しよう! ビットコインのベストの部分は、仮想通貨一般として、脱中央主義の特性から他のアセットよりもより自由。解析をオープンソースにして、コミュニティに参加して、ブログに投稿しよう

## 所感
時系列データの場合は、自己相関をみて自己回帰,移動平均などで解析をしますがどうなんでしょうか。引用元にも記述されていますがRNN, LSTMも試してみたいですね。

時系列解析ですが、[prophet](https://github.com/facebook/prophet)を使って解析してみました。ぜひご覧になってください。
[ProphetとRで仮想通貨を時系列解析してみた](https://qiita.com/tsugar/items/7af98308844a32774317)


## 参考
<em>Analyzing Cryptocurrency Markets Using Python:<em>
https://blog.patricktriest.com/analyzing-cryptocurrencies-python/