本記事ではInfluxDB + ChronografをDocker Composeを利用して動かします。また、データの書き込みをGoのInfluxDB Clientを用いて行い、Chronografでデータの可視化をしていきます。

環境構築

今回使用するDocker, Docker Compose, Goのバージョンを下記にまとめました。それぞれのバージョンは2020年6月13日の執筆時点ですべて最新バージョンとなっています。

  • Docker: 19.03.11
  • Docker Compose: 1.12.0
  • Go: 1.14.4

docker-compose.ymlファイルの中身です。 Compose file version 3 reference によれば、Dockerのバージョンによってdocker-compose.ymlに記述するversionsを適切なものに変更する必要があります。筆者環境ではDockerのバージョンが19.03.11であるため、versionsを3.8に設定しています。また、ポートはデフォルトのものをそのまま割り当てていますが、競合する場合は適宜変更してください。

docker-compose.ymlを適当なディレクトリに配置し、そのディレクトリでターミナルからdocker-composeのコマンドを実行することでInfluxDBとChronografを動作させることができます。

# docker-compose.ymlの確認
$ ls docker-compose.yml

docker-compose.yml

# Dockerコンテナの構築 & 起動
$ docker-compose up -d

Chronografの設定

InfluxDBとChronografの起動に成功したら次はChronografの設定をしてきます。ブラウザに localhost:8888 と入力することでChronografを利用することができます。この時、下記図のような画面が出てきます。ここでConnection URLのlocalhostをdocker-compose.ymlに定義したcontainer_nameに置き換えましょう。Dockerコンテナを使用している場合、locaohostのままでは繋がりません。

20200613-chronograf

Connection URLを書き換えたらAdd Connectionボタンをクリックします。以降はメインページが開かれるまではSkipを押せば大丈夫です。

InfluxDBへの書き込み

今回InfluxDBへ書き込むデータは、bitFlyerから取得できるビットコインの価格です。 bitFlyerでは、 APIドキュメント にあるとおりビットコインや取引に関する各種データを取得したり注文を出したりすることが可能です。ビットコインの価格は認証なしで誰でもGETリクエストで取得することが可能なため、API制限に気をつけながらGoのサンプルプログラムを動作させていきます。

データベースの作成

データを書き込む前にまずはデータベースの作成を行います。今回はデータベース名をtutorialとして進めていきます。下記コマンドを実行することでDockerコンテナにログインすることができ、tutorialデータベースを作成することができます。

参考: Get started with InfluxDB OSS

# Dockerコンテナにログイン
$ docker exec -it influxdb influx

# データベースを作成
> create database tutorial

データの書き込み

まずデータの書き込みをするにあたって、InfluxDBのクライアントには influxdb1-clientv2 を利用しました。

次に、bitFlyerからビットコインの価格を取得するプログラムを書いていきます。サンプルプログラムでは、ビットコインの価格に約定履歴を利用しています。またAPIコールには筆者の作成したAPI Clientである Go bitFlyer を用いているので、数行の記述でビットコインの価格を取得することができます。

以下サンプルプログラムです。下記プログラムを実行すると、bitFlyerから約定履歴を500件取得した後、InfluxDBへの書き込みを行うことができます。

下記プログラムを眺めると、タグに取引所と通貨ペアをKey-Valueで設定していることがわかります。InfluxDBのタグはオプションであるため省略することも可能です。取引所と通貨ペアを設定することで、新しい取引所や他の通貨ペアの価格を容易に追加できます。


package main

import (
    "github.com/influxdata/influxdb1-client/v2"
    "github.com/zsp2088dev/go-bitflyer/v1"
    "github.com/zsp2088dev/go-bitflyer/v1/public/executions"
    "github.com/zsp2088dev/go-bitflyer/v1/types"
    "log"
    "time"
)

func main() {
    write(toPoint(fetch()))
}

type bitcoin struct {
    timestamp time.Time
    exchange  string
    pair      string
    price     int
}

func fetch() (btcs []bitcoin) {
    c := v1.NewClient(nil)
    params := &executions.Request{
        ProductCode: types.FXBTCJPY, Count: 500,
    }
    res, _, _ := c.Executions(params)
    for _, e := range *res {
        t := e.ExecDate.In(time.FixedZone("Asia/Tokyo", 9*60*60))
        btc := bitcoin{
            timestamp: t,
            exchange:  "bitflyer",
            pair:      "btcjpy",
            price:     int(e.Price),
        }
        btcs = append(btcs, btc)
    }
    return btcs
}

func toPoint(btcs []bitcoin) (pts []*client.Point) {
    for _, btc := range btcs {
        measurement := "bitcoin"
        tag := map[string]string{"exchange": btc.exchange, "pair": btc.pair}
        fields := map[string]interface{}{"price": btc.price}
        timestamp := btc.timestamp

        point, _ := client.NewPoint(measurement, tag, fields, timestamp)
        pts = append(pts, point)
    }
    return pts
}

func write(pts []*client.Point) {
    config := client.HTTPConfig{Addr: "http://localhost:8086"}
    c, err := client.NewHTTPClient(config)
    if err != nil {
        log.Fatal(err)
    }

    bp, _ := client.NewBatchPoints(client.BatchPointsConfig{
        Database:  "tutorial",
        Precision: "s",
    })

    for _, p := range pts {
        bp.AddPoint(p)
    }

    if err := c.Write(bp); err != nil {
        log.Fatal(err)
    }
}

func read() []bitcoin {
    return nil
}

データの確認

上記プログラムを実行し終えたらInfluxDBにデータが格納されたのかを確認します。SELECT文を実行してビットコインの価格を見てみましょう。一覧が出力されたらデータが格納されています。

# Dockerコンテナにログイン
$ docker exec -it influxdb influx

# データベースを作成
> use tutorial

# データの抽出
> SELECT * FROM bitcoin

name: bitcoin
time                exchange pair   price
----                -------- ----   -----
1592109107000000000 bitflyer btcjpy 1014893
1592109120000000000 bitflyer btcjpy 1014889
1592109167000000000 bitflyer btcjpy 1014889
   .
   .

Chronografでデータを可視化

最後にChronografでデータを可視化してみます。上記の手順をすべて終了していれば、ブラウザに localhost:8888 と入力することでChronografのメインページを開くことができるはずです。データを可視化するためには、左のタブからDashboardを選択し、Add Data ボタンをクリックします。

20200613-dashboard

ここではデータの可視化するにあたってのクエリーの設定や可視化方法を選択することができます。tutorial.autogen > bitcoin > price にチェックを入れることで先程取得したビットコイン価格を可視化することができます。

20200613-graph

また、画面上部のVisualizationより、可視化方法を選択してみます。VISUALIZATION TYPESからデータに適したグラフを選択することができます。ビットコイン価格はLineでよさそうです。その他、グラフのカラーや最小値最大値、縦軸の名称などを自由に設定することができます。

20200613-visualization

最終的にカラーを変えたりタイトルを追加したりして下記図のように仕上げてみました。ダークモードでとてもおしゃれにできたと思います!ビットコイン価格取得のプログラムをリアルタイムAPIに切り替えたり、過去一ヶ月分の約定履歴を格納してみたりするとより本格的なものになるかと思います。

20200613-finally

おわりに

InfluxDB、Chronograf、Docker Compose、Goの技術を使ってデータの書き込みおよびデータの可視化を行いました。今回動作させたサンプルプログラムを応用することで、例えば暗号資産に関係することであれば、複数取引所のビットコイン価格を可視化して裁定取引のアイディアを得ることや、損益履歴の管理、取引所の遅延の可視化などを行うことができるようになります。

ここまでお付き合いいだたきありがとうございました。