みなさんはじめまして。@sam8038として活動している初心者ボッターです。 (自分の観測する狭い範囲の)Twitterで話題になっていたGraganaのローソク足対応について仮想通貨botter Advent Calendar 2021の14日目の記事として紹介します。
ローソク足
マーケットのデータ表示といえばローソク足ですね。bot制作においても時系列データの収集や可視化は重要な要素かと思います。本記事ではGrafana8.3でBeta版として実装されたCandleStickを使って取引所/通貨ペアを一覧するダッシュボードを作るまでの過程を紹介します。前提として、InfluxDB/Grafana/Telegraf がDockerコンテナとして起動しており、ダッシュボードで何かしらのメトリクスが閲覧できる状態とします。これらの構築と初期設定については記事末尾の1つ目のリンクで紹介していますので、是非参考にしてください。
データをそろえる
前に
まずは、データ収集のための準備を行います。今回telegrafコンテナの中でDockerコマンドを使用したいので、コンテナ内で使えるdockerコマンドをインストールするDockerfileを書きます。以下のような内容でdocker-compose.ymlと同じディレクトリに作成します。(133はホストマシンのdockerグループIDです。動作しない場合はgetent group docker
で確認したIDに変更が必要です。)
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のマウントも必須です。
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プロジェクトで確認することができます。
[[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での作業になります。
変数の設定
パネルを動的に生成したいので、パネルの設定内に渡す変数を定義しておきます。
- ダッシュボードを追加します。
- 設定をします
- Variablesブレードから新しく追加を選択し集計用の足を設定します。図のような感じで設定して保存してください。
- 次は通貨ペアの設定です。クエリには
SHOW TAG VALUES WITH KEY = "symbol"
、正規表現は空白でOKです。絞り込みたい場合に追加すると良いです。データが正常に収集されていればプレビューに通貨ペアが表示されるはずです。 - 最後に取引所を設定します。クエリには
SHOW TAG VALUES WITH KEY = "exchange"
あとは図のように設定して保存してください。これもプレビューに取引所が表示されるはずです。 - こんな感じになっていればOKです。
パネルの追加
-
クエリは以下のをペーストして、あとは画像の通り設定してください。クエリ内の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)
データを分析する
-
分析のために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()
-
例として5分の移動平均をプロットしてみます。めちゃくちゃ簡単ですね。
ax = ohlcv.close.rolling("5min").mean().plot(label="moving average") ohlcv.close.plot(ax=ax) ax.legend()
さいごに
最後まで読んでいただきありがとうございました。私自身、21年5月から機械学習による自動取引botの開発に着手し最近ようやく運用開始に至りました。成績はまだまだですが、ここまでには様々な記事や情報発信に助けてもらいました。一方で、環境構築や分析基盤・運用回りの記事はまだまだ少ないと感じています。本業では、いかに安定した/汎用的な/バグの少ないシステムを構築するかということをいつも考えているので、この知識を活かして界隈に少しでも還元していけたらと思っています。
今回はccxtを使うことで様々な取引所・通貨ペアを横断してデータが収集できました。作ったのは収集部分のDockerイメージだけですが非常に安定して動作しています。制約として、収集間隔や取引所の配信タイミングの都合上、反映までに最大1分程度のラグが発生します。短期間の取引のデータソースとしては都合が悪いかもしれませんが、数分〜数時間オーダでの取引の上では小さな誤差と考えています。
私は、この情報をもとに独自のバーを計算したり、取引所・通貨ペアを横断して分析をしたり、バックテストを行ったり、エントリーのための推論を行なったり、ローカルのデータソースとして活用しています。みなさんのbot生活に少しでも貢献できれば幸いです!
参考