統計学の話が出てくるが、私も学習者なので特別詳しいわけではない。間違っている箇所があるかもしれないのでご了承願いたい。
BitMEXでは「デプスチャート」というものが使われている。
少なくとも統計学の専門用語として私は聞いたことがないが、恐らくヒストグラムの累積度数分布表を左右に重ねたグラフを表現していると思われる。
例えば1クラスのテストの点数であれば「Aさん10点、Bさん30点、Cさん50点」と3本の棒グラフにするのもよいだろう。
ではこれが全国の生徒それぞれの点数の分布だったらどうか。
上記の例と同じ方法では情報が多すぎて棒グラフでは表現し難い。
そこで「0-10点」「11-20点」...「91-100点」のようにある程度区分を分けてその中に何人いるかをグラフ化すると忽ち視認性が上がる。
これがヒストグラムだ。
板情報も1ビットコイン100万円のような数字になるが、1円単位で板が別れている。
このため先ほどと同じように棒グラフではデータが多すぎて分布がわからない。
そこでヒストグラムを使うと良い。
しかしこれにも問題がある。正規分布のようにキレイに山がかける分布であればそのままヒストグラムで表示してもよいが各投資家が自由な箇所に指値を置けるため価格と数量の分布はバラバラでヒストグラムにしてもギザギザのグラフが出来上がってしまう。
難しい気がするがこれが正にBitMEXの「デプスチャート」に似ているもので、小さい階級(範囲)から順に足していった表である。
もともと板取引は現在価格に近い順から約定していくという性質上まさに累積度数分布表が最も視認性が高いチャートの一つだと言ってよい。
正直私がうまく説明できていない気がするので、統計学が気になればぜひとも「ヒストグラム」を調べてみてほしい。
とはいえ説明するまでもなくある程度の取引所ではこのように板を纏めて表示していると思われる。
Chart.jsには棒グラフはあるが、ヒストグラムが存在しない。D3.jsにはヒストグラム関係のオプションが有るようだが残念ながらChart.js系列は自前でコードを用意しなければならない。
厳密には棒グラフとヒストグラムは違うもの(ヒストグラムは棒と棒の間にスペースがない)のだが見た目がほぼ棒グラフと同一なのでコード次第で再現は可能だ。
BarChart.js
のモジュールとして実装した
export const histogram = (message, range) => {
//bids(買い板)のみ実装
//price順で整列し直す(bitFlyerが順番を保証していないため)
message.bids.sort((a, b) => {
//降順
return b.price - a.price
});
//ヒストグラムを生成(階級幅:range)
const max_price = message.bids[0].price //階級を確定するためには最大価格が必要
let data = []
for (let bid of message.bids) {
//階級=配列番号を計算
const bin = Math.floor( (max_price - bid.price) / range)
// 3/25 次のコードより変更 data[bin] = bid.size
// データが加算されていなかったバグ修正
!data[bin] ? data[bin] = bid.size : data[bin] = data[bin] + bid.size
}
//ラベルを設定
let labels = []
for (let i = 0; i <= data.length - 1; i++) {
const label = max_price - (range * i)
labels.push(label)
//累積度数化
if (!data[i]) { data[i] = 0 }
i != 0 ? data[i] = data[i - 1] + data[i] : null
}
const board_data = {
labels,
datasets: [
{
label: "bid",
data,
backgroundColor: "blue",
},
]
}
return board_data
}
重要なポイントを見ていく
export const histogram = (message, range) => {
引数で渡されるmessageはそのままbitmex Realtime APIから送られてくる板情報だ。
ask
(連想配列), bid
(連想配列), mid_price
が入っている。 range
としたのは階級の範囲である。
尚、統計学では階級の範囲についてはチャート作成者が自由に決めて良い事になっている。
3/25:式がわかりにくかったので修正。結果は変わりません。
const bin = Math.floor( (max_price - bid.price) / range)
今回はこのコードによって配列の要素1つに1階級を入れる設計だ。この他の方法が思い当たらなかった。
このあたりのコードについてはbidが買い板(高い価格から低い価格へ累積する)という性質も含め少々ロジック解釈が複雑なので解説が難しい。そこまできになる場合は読んでみるのも良い。
★私のロジック(解釈)自体が間違っている可能性もあるので注意願いたい。
//累積度数化
if (!data[i]) { data[i] = 0 }
i != 0 ? data[i] = data[i - 1] + data[i] : null
丁度ラベルを生成するコードがデータを一周するforなので、 合わせて累積度数を計算するコードを置いた。
if文はデータが存在しない要素があるため(だれも指値を置いていない箇所)初期化している。
要素番号1から順番に前の配列をプラスするだけで累計を求めている。
時間が足りず今回もbid情報だけとなったのでデプスチャートとしては完成していないのでご了承願いたい。時間が許せば続きも作成したい。
注意(3/25): BitMEXは右側が売り(Ask)グラフのでした。これは真逆になっているのでこの形状だと混乱するかもしれません。次回のask実装時にBitMEXとフォーマットを統一する予定です。
これがなんの約にたつのか?という疑問だけが常に頭をよぎる。
ただ、bitFlyerに対して所謂「デプスチャート」を公開しているサイトを少なくとも私は知らない(探せばあるのだろうが)