2020-04-06

【謎のチャート】ティッカー(Ticker)を可視化【ver. 0.1.0】

Vue.js x chart.jsで実装している「謎のチャート」にてTickerを可視化する。

Article Image

謎のチャート

謎のチャートとは

Vue.js と vue-chart.js によってWEBアプリとしてbitFlyerから流れてくる「板データ」を可視化する実験。

板情報可視化に関する実験の詳細を知りたい場合は私の過去の記事(難易度:ちょっとむずかしい/非常にめんどい)

今回の読者ターゲット

かなりマニアック。

Vue.jsはともかくvue-chart.jsを使っていくので学習コストが必要。

難易度的には板情報の可視化より、Tickerの可視化のほうが先にやるべきだった。

前提

  • bitFlyerのRealtime APIの公式サンプルコード(socket.io)が理解できる(難易度:ふつう)
  • vue-chart.jsを最低限理解している(難易度:難しい)

では、早速本題にはいっていく。

チャンネルのサブスクライブ

私のYoutubeチャンネルをサブスクしなさいと言っているわけではない。socket.ioで情報(channel)を受信することを「subscribe」と公式に呼ぶ。

Tickerのチャンネルは lightning_ticker_プロダクトコード なので、FXのTickerを見たい場合は次のコードのようにする。

    socket.on("connect", () => {
      const publicChannels = [
        "lightning_ticker_FX_BTC_JPY" //これがTicker
      ];
      for (const ch of publicChannels) {
        socket.emit("subscribe", ch, err => {
          if (err) {
            console.error(ch, "Subscribe Error:", err);
            return;
          }
          console.log(ch, "Subscribed.");
        });
      }
    //まだ続く

vue-chart.js用のjsファイルを新規作成

今回は「TickerLine.js」とした。

やたら易しいvue-chart.js解説で紹介しているように、vue-chart.jsは新しいグラフを作成する時は毎回別ファイルで用意するという決まりである。

ただ、これ自体は簡単で記事内で紹介しているプログラムをまずはコピーして、必要な箇所を修正すればよい。

今回は棒グラフではなく線グラフ(Line)である箇所だけ変更する(2箇所で指定)

TickerLine.js

import { Line, mixins } from 'vue-chartjs' // ここにLine
const { reactiveProp } = mixins

export default {
    mixins: [Line,reactiveProp], // ここにもLine
    props: ['options'],
    mounted() {
        this.renderChart(this.data, this.options)
    }
}

今回は上と同じjsに入ってきたTickerの生データを処理してchart.js描画用のオブジェクトに整形しreturnする関数を実装した。

export const renewTicker = (message, datacollection, maxCnt) => {

    //ラベルは「時:分:秒」で表示
    const date = new Date(message.timestamp)
    const time = date.getHours() + ":" + date.getMinutes() + ":" + date.getSeconds()

    //Tickerの生データ(message)をグラフ用にpush
    datacollection.labels.push(time)
    datacollection.datasets[0].data.push(message.best_bid)
    datacollection.datasets[1].data.push(message.best_ask)
    datacollection.datasets[2].data.push(message.ltp)

    //画面に表示する件数を超えたらshiftで削る
    if (datacollection.labels.length > maxCnt) {
        datacollection.labels.shift()
        datacollection.datasets.forEach((array) =>{
            array.data.shift()
        })
    }
  
    //ラベルの通り表示する線は3本
    //上からbid,ask,ltp
    const return_datacollection = {
        labels: datacollection.labels,
        datasets: [
            {
                label: "bid",
                data: datacollection.datasets[0].data,
                fill: false,
                borderColor: "green"
            },
            {
                label: "ask",
                data: datacollection.datasets[1].data,
                fill: false,
                borderColor: "red"
            },
            {
                label: "Last Trade Price",
                data: datacollection.datasets[2].data,
                fill: false,
                borderColor: "gray"
            },
        ]
    }

    return return_datacollection
}

vue側

必ず読み込む側のvueファイルでインポートしておく。

import TickerLine, { renewTicker } from "./TickerLine.js";

export default {
  components: {
    TickerLine
  },

テンプレート部

<TickerLine :chart-data="datacollection_ticker" :options="options_ticker" />

data部にdatacollection_tickerの初期化を忘れないように。

    datacollection_ticker: {
      labels: [],
      datasets: [
        {
          label: [],
          data: []
        },
        {
          label: [],
          data: []
        },
        {
          label: [],
          data: []
        }
      ]
    }

vue-chart.jsの決まりごと!必ずmountedでオプションを設定すること。

mounted() {
      this.options_ticker = {
        responsive: true, //レスポンシブにサイズが変わる
        maintainAspectRatio: false, //縦サイズを固定する
        scales: {
          yAxes: [
            {
              position: "right" //Y軸のラベルを右にしている
            }
          ]
        }
      }

socket.ioもmountedで登録しておく。

    const socket = io("https://io.lightstream.bitflyer.com", {
      transports: ["websocket"] // specify explicitly
    });

    socket.on("connect", () => {
      const publicChannels = [
        "lightning_ticker_FX_BTC_JPY"
      ];
      for (const ch of publicChannels) {
        socket.emit("subscribe", ch, err => {
          if (err) {
            console.error(ch, "Subscribe Error:", err);
            return;
          }
          console.log(ch, "Subscribed.");
        });
      }
      //ticker
      socket.on("lightning_ticker_FX_BTC_JPY", message => {
          this.datacollection_ticker = renewTicker(
            message, //第一引数にTicker
            this.datacollection_ticker,  //データを追記して返す為渡す
            30 //表示する最大数 これはユーザーが入力出来るように後に変更
           )
        }
      });

完成

完成品 - 謎のチャートはこちら

サンプル動画

これまた探せば何処かにありそうだが無骨に現在価格を表示するよりかはより詳細が目視できるようになった。

さいごに

あいかわらずこれだけの可視化で勝てるほど甘くない。ただ、とりあえず出来ることを淡々とこなすことも重要な一歩だ。

あとは約定あたりでなにかアイデアがあれば可視化してみたい。



この記事をシェア


謎の技術研究部 (謎技研)