見出し画像

Chart.jsでリアルタイムチャートを描画する[Javascript][Chart.js][Websocket]

こんにちわ、ニッケルメッキです。
さて、最近は仮想通貨bot界もレッドオーシャンになり過ぎているのかさっぱり儲かりません。
つきましては、データの可視化などを通し利益を出す気づきを得られないかと画策しております。

その第一弾として、今現在の値動きにフォーカスを当てようと思い現在時刻ベースで値動きを眺めてみることにしました。

今日、公開するコードはその際に作成したチャート描画スクリプトになります。コードは何かしらいじくって使えるように、無駄なCSSリセットやVue.jsなども含まれています。
何かの参考になればと思います。

以下コード。 ※ライブラリはダウンロードするなどしてください。

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta name='viewport' content='width=device-width, initial-scale=1'>
   <!-- インストール方法など https://www.chartjs.org/ -->
   <script src="moment.js"></script>
   <script src="chart.js"></script>
   <script src="chartjs-plugin-streaming.js"></script>
   <!-- vue.jsはチャート自体には不要 -->
   <script src="vue.js"></script>
   <title>bitFlyer Realtime Chart</title>
</head>
<body>
  <!-- App main container -->
   <section id="app">
       <!-- chart container -->
       <section class="chart-container">
           <canvas id="btc_jpy"></canvas>
       </section>
       <section class="chart-container">
           <canvas id="fx_btc_jpy"></canvas>
       </section>
       <section class="chart-container">
           <canvas id="sfd"></canvas>
       </section>
   </section>

   <!-- css resets etc.. -->
   <style type="text/css">
       html, body,
       h1, h2, h3, h4, h5, h6,
       a, p, span,
       em, small, strong,
       sub, sup,
       mark, del, ins, strike,
       abbr, dfn,
       blockquote, q, cite,
       code, pre,
       ol, ul, li, dl, dt, dd,
       div, section, article,
       main, aside, nav,
       header, hgroup, footer,
       img, figure, figcaption,
       address, time,
       audio, video,
       canvas, iframe,
       details, summary,
       fieldset, form, label, legend,
       table, caption,
       tbody, tfoot, thead,
       tr, th, td {
           margin: 0;
           padding: 0;
           border: 0;
       }
   </style>

   <!-- App scripts -->
   <script>
       // Vue インスタンス(App) ※使う人用?
       const app = new Vue({
           el: '#app',
           data: {
               message: ''
           }
       })

       // Websocketの設定
       app.ws = new WebSocket('wss://ws.lightstream.bitflyer.com/json-rpc');
       app.ws_params = [{  // リクエストパラメータ
           "method": "subscribe",
           "params": {
               "channel": "lightning_executions_BTC_JPY",
           }
       }, {
           "method": "subscribe",
           "params": {
               "channel": "lightning_executions_FX_BTC_JPY"
           }
       }];
       app.ws_results = {'ltp': []} // Websocket message格納用名前空間

       // Websocket 接続開始
       app.ws.addEventListener('open', function(e){
           app.ws.send(JSON.stringify(app.ws_params));
       });

       // Websocket message受信時の処理
       app.ws.addEventListener('message', function(e){
           data = JSON.parse(e.data)['params'];  // Jsonデコード
           channel = data['channel']
           message = data['message'];
           // 最新の価格のみ抽出し、該当パラメータへ価格をセット
           if (channel == 'lightning_executions_BTC_JPY'){
               app.ws_results['ltp']['btc_jpy'] = parseInt(message[message.length - 1]['price'])
           } else if (channel == 'lightning_executions_FX_BTC_JPY'){
               app.ws_results['ltp']['fx_btc_jpy'] = parseInt(message[message.length - 1]['price'])
           }
       });

       // Chart.jsの設定
       app.ctx_btc_jpy = document.getElementById('btc_jpy').getContext('2d');  // DOM要素の取得
       app.ctx_fx_btc_jpy = document.getElementById('fx_btc_jpy').getContext('2d');
       app.ctx_sfd = document.getElementById('sfd').getContext('2d');

       app.chart_btc_jpy = new Chart(app.ctx_btc_jpy, {  // チャートインスタンス
           type: 'line',  // チャート計上 line -> 折れ線グラフ
           data: {  // チャートデータの設定
               datasets: [{  // データセット(複数指定可能)
                   label: 'BTC_JPY', // データラベル
                   backgroundColor: 'rgba(0, 0, 0, 0.2)',  // 背景色(fill)
                   data: []  // データ格納用配列
               }]
           },
           options: {  // チャートオプションの設定
               maintainAspectRatio: false,  // リサイズ時にアスペクト比を固定するか(True=固定)
               layout: {  // チャートレイアウト
                   padding: {
                       left: 0,
                       right: 0,
                       top: 0,
                       bottom: 0
                   }
               },
               scales: {  // スケールの設定
                   xAxes: [{  // x軸の設定
                       type: 'realtime',  // リアルタイム描画
                       realtime: {
                           delay: 2000,  // 滑らかに表示したい場合?
                           onRefresh: function(chart) {
                               // データの追加
                               app.chart_btc_jpy.data.datasets.forEach(function(v, i ,datasets) {
                                   datasets[i].data.push({
                                       x: Date.now(),  // 現在時刻
                                       y: app.ws_results['ltp']['btc_jpy']  // 価格
                                   });
                               });
                           }
                       }
                   }]
               }
           }
       });
       app.chart_fx_btc_jpy = new Chart(app.ctx_fx_btc_jpy, {
           type: 'line',
           data: {
               datasets: [{
                   label: 'FX_BTC_JPY',
                   backgroundColor: 'rgba(0, 0, 0, 0.2)',
                   data: []
               }]
           },
           options: {
               maintainAspectRatio: false,
               layout: {
                   padding: {
                       left: 0,
                       right: 0,
                       top: 0,
                       bottom: 0
                   }
               },
               scales: {
                   xAxes: [{
                       type: 'realtime',
                       realtime: {
                           delay: 1000,
                           onRefresh: function(chart) {
                               app.chart_fx_btc_jpy.data.datasets.forEach(function(v, i ,datasets) {
                                   datasets[i].data.push({
                                       x: Date.now(),
                                       y: app.ws_results['ltp']['fx_btc_jpy']
                                   });
                               });
                           }
                       }
                   }]
               }
           }
       });
       app.chart_sfd = new Chart(app.ctx_sfd, {
           type: 'line',
           data: {
               datasets: [{
                   label: 'SFD',
                   backgroundColor: 'rgba(0, 0, 0, 0.2)',
                   data: []
               }]
           },
           options: {
               maintainAspectRatio: false,
               layout: {
                   padding: {
                       left: 0,
                       right: 0,
                       top: 0,
                       bottom: 0
                   }
               },
               scales: {
                   xAxes: [{
                       type: 'realtime',
                       realtime: {
                           delay: 1000,
                           onRefresh: function(chart) {
                               app.chart_sfd.data.datasets.forEach(function(v, i ,datasets) {
                                   stock_ltp = app.ws_results['ltp']['btc_jpy'];
                                   fx_ltp = app.ws_results['ltp']['fx_btc_jpy'];
                                   datasets[i].data.push({
                                       x: Date.now(),
                                       y: (fx_ltp - stock_ltp) / stock_ltp * 100
                                   });
                               });
                           }
                       }
                   }]
               }
           }
       });
       // リサイズ時へのグラフサイズの対応
       app.chart_btc_jpy.canvas.parentNode.style.height = '32vh';
       app.chart_btc_jpy.canvas.parentNode.style.width = '98vw';
       app.chart_fx_btc_jpy.canvas.parentNode.style.height = '32vh';
       app.chart_fx_btc_jpy.canvas.parentNode.style.width = '98vw';
       app.chart_sfd.canvas.parentNode.style.height = '32vh';
       app.chart_sfd.canvas.parentNode.style.width = '98vw';

   </script>
</body>
</html>

[動作した時の図]

画像1


この記事が気に入ったら、サポートをしてみませんか?気軽にクリエイターを支援できます。

14
コメントを投稿するには、 ログイン または 会員登録 をする必要があります。