2020-03-26

Node.js x bitFlyer API #9 板データの可視化(4) デプスチャート完成

BitMEXのデプスチャートに似たbitFlyerのデプスチャートが完成した

Article Image

完成動画

特徴

  • 一つのチャートにBidとAskを纏めた
  • 板の厚みに応じて中央が左右に動く(画像は買い板が厚いため右に中央が押している)
  • スナップ情報のみ(更新は遅い)

メリット

売りと買いどちらの板が厚いかが目視しやすいというメリットを発見した。

BitMEXと違い厚みに応じて中央が左右に動くがこれはこれで分かりやすい。

今日のコード

前回の板表示がBitMEXと反対側だったので今回からわかりやすくBitMEXとおなじになるよう修正する。

DepthChart.js というファイルを切ってモジュール化した。

export const depthChart = (message,range) => {

    
    const ask = askHistogram(message,range)
    const bid = bidHistogram(message,range)

    const labels = bid.labels.concat(ask.labels)
    const data = bid.data.concat(ask.data)

    let backgroundColor = new Array(bid.labels.length + ask.labels.length )
    backgroundColor.fill("green",0,bid.labels.length )
    backgroundColor.fill("red",bid.labels.length,bid.labels.length + ask.labels.length )

    const board_data = {
        labels,
        datasets: [
            {
                label: "Depth Chart",
                data,
                backgroundColor,
            },
        ]
    }


    return board_data
}

askbidの定数にそれぞれ2つのヒストグラムを読み込む。

コードが冗長になるのでaskHistogram()の中身だけ記述する。

const askHistogram = (message, range) => {

    //asks(売り板)

    //price順で整列し直す(bitFlyerが順番を保証していないため)
    message.asks.sort((a, b) => {
        // 昇順
        return a.price - b.price
    });

    //ヒストグラムを生成(階級幅:range)
    const min_price = message.asks[0].price //階級を確定するためには最大価格が必要
    let data = []
    for (let ask of message.asks) {
        //階級=配列番号を計算
        const bin = Math.floor( (ask.price - min_price) / range)
        !data[bin] ? data[bin] = ask.size : data[bin] = data[bin] + ask.size
    }

    //ラベルを設定
    let labels = []
    for (let i = 0; i <= data.length - 1; i++) {
        const label = min_price + (range * i)
        labels.push(label)

        // //累積度数化
        if (!data[i]) { data[i] = 0 }
        i != 0 ? data[i] = data[i - 1] + data[i] : null

    }

    return {labels, data}
}

要点

concat

    const labels = bid.labels.concat(ask.labels)
    const data = bid.data.concat(ask.data)

配列と配列をくっつける処理にconcatを使用する。もともとそのために用意された関数。文法は調べればよいが、このような関数があることだけは知っておきたい。

これは2つのチャートを一つに纏めている。チャートは左から順にデータが入っていくで、左側にくるBid(買い)にask(売り)をマージするイメージだ。

fill

    let backgroundColor = new Array(bid.labels.length + ask.labels.length )
    backgroundColor.fill("green",0,bid.labels.length )
    backgroundColor.fill("red",bid.labels.length,bid.labels.length + ask.labels.length )

datasets(Chart.js)のプロパティにbackgroundColorがある。値を一つだけ渡してやれば全体がその色になるが、ここに配列を渡してやると棒1本が配列に指定されたそれぞれの色で描画できる。

ここでは棒1本に対して1要素生成し、左を緑、右を赤に分けている。

fillというメソッドは指定したデータで配列を埋めるコードだ。知らなければ別のコードで代用してしまいそうだがスマートな記述となるため覚えておきたい。

コード一番下の"red"の例のように数字を指定して途中から埋めることもできる。

オブジェクトのreturn

return {labels, data}

ES6よりオブジェクトがreturnできる。これにより複数の値をreturnするとき受け取った側の変数呼び出しが楽になる。

Bid側のラベルと累積度数計算のコード

上ではAsk(売り)側のコードを記述したが、Bid(買い)側のコードは累積度数が逆からの計算になるため参考にしていただきたい。

    //ラベルを設定
    let labels = []
    for (let i = 0; i <= data.length - 1; i++) {
        const label = (range * i) + min_price
        labels.push(label)
    }
    
    // iが配列の後ろから処理している点に注意
    for(let i = data.length - 1; i >= 0; i--){
        //累積度数化
        if (!data[i]) { data[i] = 0 }
        i != data.length - 1 ? data[i] = data[i + 1] + data[i] : null
    }

    return {labels,data}

さいごに

公開するシステムに取り込むのであればもっといろいろオプション設定など実装できそうだが、とりあえず一段落してしたのでさらなる分析の手法を考えていきたい。

ピンポイントで板が厚い箇所は分かりにくいが全体的な厚みが把握できるメリットが発見できただけでもよしとする。



この記事をシェア


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