19
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Last updated at Posted at 2021-12-03

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

ローソク足

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

Screen Shot 2021-12-03 at 0.50.01.png

データをそろえる

前に

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

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のマウントも必須です。

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プロジェクトで確認することができます。

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

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

docker-compose down && docker-compose up -d

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

$ 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
  2. 設定をしますScreen Shot 2021-12-04 at 1.23.09.png
  3. Variablesブレードから新しく追加を選択し集計用の足を設定します。図のような感じで設定して保存してください。Screen Shot 2021-12-04 at 1.24.58.png
  4. 次は通貨ペアの設定です。クエリにはSHOW TAG VALUES WITH KEY = "symbol"、正規表現は空白でOKです。絞り込みたい場合に追加すると良いです。データが正常に収集されていればプレビューに通貨ペアが表示されるはずです。 Screen Shot 2021-12-04 at 1.32.33.png
  5. 最後に取引所を設定します。クエリにはSHOW TAG VALUES WITH KEY = "exchange"あとは図のように設定して保存してください。これもプレビューに取引所が表示されるはずです。Screen Shot 2021-12-04 at 1.39.50.png
  6. こんな感じになっていればOKです。Screen Shot 2021-12-04 at 1.40.20.png

パネルの追加

  1. パネルを追加していきましょう。右上の+ボタンからパネルが追加できます。Screen Shot 2021-12-04 at 1.34.49.png

  2. クエリは以下のをペーストして、あとは画像の通り設定してください。クエリ内のexchangeやsymbolやbarsizeは前章で設定した変数に代入された値が入ります。

    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

  1. タイトルとパネルの変数の設定をしておき、適用を押下します。Screen Shot 2021-12-04 at 1.55.07.png
  2. あとはこんな感じで通貨ペア・取引所・足が選択できるはずです。お疲れ様でした! Screen Shot 2021-12-04 at 1.58.46.png
  3. 忘れず保存しておきましょう。

データを分析する

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

    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

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

    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

さいごに

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

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

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

参考

19
17
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
19
17

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?