ローソク足を自炊してGrafanaで描画してみた

みなさんはじめまして。[@sam8038](https://twitter.com/sam8038)として活動している初心者ボッターです。 (自分の観測する狭い範囲の)Twitterで話題になっていたGraganaのローソク足対応について仮想通貨botter Advent Calendar 2021の14日目の記事として紹介します。

https://qiita.com/advent-calendar/2021/botter

# ローソク足
マーケットのデータ表示といえばローソク足ですね。bot制作においても時系列データの収集や可視化は重要な要素かと思います。本記事ではGrafana8.3でBeta版として実装されたCandleStickを使って取引所/通貨ペアを一覧するダッシュボードを作るまでの過程を紹介します。前提として、InfluxDB/Grafana/Telegraf がDockerコンテナとして起動しており、ダッシュボードで何かしらのメトリクスが閲覧できる状態とします。これらの構築と初期設定については記事末尾の１つ目のリンクで紹介していますので、是非参考にしてください。

![Screen Shot 2021-12-03 at 0.50.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/5791a90f-02fb-fc38-01ed-7638aaeaf086.png)


# データをそろえる
## 前に


まずは、データ収集のための準備を行います。今回telegrafコンテナの中でDockerコマンドを使用したいので、コンテナ内で使えるdockerコマンドをインストールするDockerfileを書きます。以下のような内容でdocker-compose.ymlと同じディレクトリに作成します。(133はホストマシンのdockerグループIDです。動作しない場合は`getent group docker`で確認したIDに変更が必要です。)

```Dockerfile:Dockerfile
FROM telegraf
RUN apt update && apt install -y jq
COPY --from=docker /usr/local/bin/docker /usr/local/bin/
RUN groupadd -g 133 docker 
RUN gpasswd -a telegraf docker
```

次にdocker-compose.ymlの設定を修正します。Dockerイメージの代わりにDockerfileでビルドしたイメージを使用するので、imageキーをコメントアウトして、`build: .`をかわりに追記します。また、docker.sockのマウントも必須です。


```yml:docker-compose.yml
  telegraf:
#    image: telegraf
    build: .
    container_name: telegraf
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock #必須
```


## 設定
次にデータ収集の設定を行います。telegraf.confに以下を追記しておくと、20s毎にコマンドを実行してinfluxdbにデータを送信してくれます。記事末尾にプロジェクトへのリンクを記載しておきました。CCXTで対応している取引所に対応しています。取引所一覧は`docker run --rm sammrai/fetch_ohlcv:latest -h`または[ccxtプロジェクト](https://github.com/ccxt/ccxt#supported-cryptocurrency-exchange-markets)で確認することができます。



```conf:telegraf.conf
[[inputs.exec]]
commands = ["docker run --rm sammrai/fetch_ohlcv:latest --exchanges kucoin kraken --symbols BTC/USDT ETH/USDT"]
timeout = "20s"
data_format = "influx"
interval = "20s"
```




ここまでで、おそらく以下のようなファイル構成になっているはずです。

```
.
L docker-compose.yml
L Dockrfile
L telegraf.conf
```

保存したら一度コンテナを再起動しましょう。

```shell
docker-compose down && docker-compose up -d
```

ログを確認し、エラーなどが出ていなければOKです。上記のいずれかの設定に問題があればエラーが出ます。

```shell
$ docker-compose logs -f telegraf

# 以下はErrorとWaringのログの例です。
telegraf    | 2021-12-04T11:50:10Z E! [inputs.exec] ~~~
telegraf    | 2021-12-04T11:50:10Z W! [inputs.exec] ~~~
```



# ダッシュボードの作成
ここからはGrafanaでの作業になります。

## 変数の設定
パネルを動的に生成したいので、パネルの設定内に渡す変数を定義しておきます。

1. ダッシュボードを追加します。![Screen Shot 2021-12-04 at 1.22.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/1c775a2a-f0e6-7649-2eff-354bc939dde4.png)
1. 設定をします![Screen Shot 2021-12-04 at 1.23.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/cf873305-46b2-a0fb-8e40-74a959e473cb.png)
1. Variablesブレードから新しく追加を選択し集計用の足を設定します。図のような感じで設定して保存してください。![Screen Shot 2021-12-04 at 1.24.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/6261528b-8b3d-abd3-94d7-a1221766d56e.png)
1. 次は通貨ペアの設定です。クエリには`SHOW TAG VALUES WITH KEY = "symbol"`、正規表現は空白でOKです。絞り込みたい場合に追加すると良いです。データが正常に収集されていればプレビューに通貨ペアが表示されるはずです。 ![Screen Shot 2021-12-04 at 1.32.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/a4ae1631-6080-8254-6a88-e5649b9082ad.png)
1. 最後に取引所を設定します。クエリには`SHOW TAG VALUES WITH KEY = "exchange"`あとは図のように設定して保存してください。これもプレビューに取引所が表示されるはずです。![Screen Shot 2021-12-04 at 1.39.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/d503b50e-beae-80be-8c1b-988084f75b86.png)
1. こんな感じになっていればOKです。![Screen Shot 2021-12-04 at 1.40.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/aeae3983-9730-1ef3-2819-a5ae9dce5ffc.png)


## パネルの追加

1. パネルを追加していきましょう。右上の＋ボタンからパネルが追加できます。![Screen Shot 2021-12-04 at 1.34.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/e0e48b92-5f50-21f0-090b-240da6c3fd03.png)
1. クエリは以下のをペーストして、あとは画像の通り設定してください。クエリ内のexchangeやsymbolやbarsizeは前章で設定した変数に代入された値が入ります。

    ```SQL
    SELECT first("open") as open, max("high") as high , min("low") as low, last("close") as close, sum("volume") as volume FROM "exchange" WHERE ("exchange" =~ /^$exchange$/ AND "symbol" =~ /^$symbol$/) AND $timeFilter GROUP BY time($barsize)
    ```
![Screen Shot 2021-12-04 at 1.54.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/54e1f885-0732-a17a-c631-18c2e80209aa.png)
1. タイトルとパネルの変数の設定をしておき、適用を押下します。![Screen Shot 2021-12-04 at 1.55.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/74f3537a-293b-7938-5523-2f866c8329fc.png)
1. あとはこんな感じで通貨ペア・取引所・足が選択できるはずです。お疲れ様でした！ ![Screen Shot 2021-12-04 at 1.58.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/6e2cea1f-2b89-07fc-afae-6978a6599133.png)
1. 忘れず保存しておきましょう。

# データを分析する

1. 分析のためにDBからデータを取得してみます。pandasのデータフレームがohlcvで返ってきます。

	```py
	from influxdb_client import InfluxDBClient

	client = InfluxDBClient(url="http://192.168.32.70:8086", # influxDBのサーバアドレス
							token="my-super-secret-auth-token", org="my-org")

	def fetch_table(exchange="Liquid", symbol="BTC/JPY", timeframe="1m", since="-1d", measurement="exchange", bucket="my-bucket"):
		query_api = client.query_api()

		tables = query_api.query_data_frame(f'''
		from(bucket: "{bucket}")
		|> range(start:  {since}, stop: now())
		|> filter(fn: (r) => r["exchange"] == "{exchange}")
		|> filter(fn: (r) => r["symbol"] == "{symbol}")
		|> filter(fn: (r) => r["timeframe"] == "{timeframe}")
		|> filter(fn: (r) => r["_measurement"] == "{measurement}")
							''')
		if type(tables) == list:
			df = pd.concat(tables, axis=0)
		else:
			df = tables
		df = df.pivot_table('_value', ['_time'], '_field', aggfunc='last')
		return df

	ohlcv = fetch_table()
	```
![Screen Shot 2021-12-11 at 1.07.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/5ea64094-e756-ff98-5e89-9ae282ea581e.png)

1. 例として５分の移動平均をプロットしてみます。めちゃくちゃ簡単ですね。

	```py
	ax = ohlcv.close.rolling("5min").mean().plot(label="moving average")
	ohlcv.close.plot(ax=ax)
	ax.legend()
	```
![Screen Shot 2021-12-11 at 1.18.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/96637/02c09bef-c77e-4b0c-4e4d-b79a2b08b486.png)


# さいごに
最後まで読んでいただきありがとうございました。私自身、21年5月から機械学習による自動取引botの開発に着手し最近ようやく運用開始に至りました。成績はまだまだですが、ここまでには様々な記事や情報発信に助けてもらいました。一方で、環境構築や分析基盤・運用回りの記事はまだまだ少ないと感じています。本業では、いかに安定した/汎用的な/バグの少ないシステムを構築するかということをいつも考えているので、この知識を活かして界隈に少しでも還元していけたらと思っています。

今回はccxtを使うことで様々な取引所・通貨ペアを横断してデータが収集できました。作ったのは収集部分のDockerイメージだけですが非常に安定して動作しています。制約として、収集間隔や取引所の配信タイミングの都合上、反映までに最大１分程度のラグが発生します。短期間の取引のデータソースとしては都合が悪いかもしれませんが、数分〜数時間オーダでの取引の上では小さな誤差と考えています。

私は、この情報をもとに独自のバーを計算したり、取引所・通貨ペアを横断して分析をしたり、バックテストを行ったり、エントリーのための推論を行なったり、ローカルのデータソースとして活用しています。みなさんのbot生活に少しでも貢献できれば幸いです!



# 参考

https://qiita.com/sammrai/items/0c329ac7aa8b100b66a8

https://github.com/sammrai/fetch_ohlcv

https://grafana.com/docs/grafana/latest/visualizations/candlestick/