株価のローソク足チャートを描いてみます。これを描いてみたかったので、D3.js触ってみたんですよね。D3.jsには「TechanJS」というファイナンス用のライブラリが存在しており、これを利用することで簡単にチャートを作成できます。
TechanJSのギャラリー。いろんな表やオシレーターのサンプルがあります。
Gallery · andredumas/techan.js Wiki · GitHub
このライブラリを利用しなくともD3.jsだけでローソク足チャートは作成できますが、まあライブラリ使ったほうが圧倒的に楽ですよ。ということで、以下のようなチャートを作成してみました。昨年末のトヨタ自動車のチャートです。青い線は25日線です。
前回の投稿を参考に、Rails上でチャートを描画してみます。
RailsでD3.jsを使う - goodbyegangsterのブログ
コントローラの作成
「candlestick」というコントローラに、indexとlistというアクションを作成しておきます。
$ rails generate controller candlestick index list
D3.jsとTechanJSの参照設定
全ページで参照できるようにするため、「application.html.erb」ファイルに以下を記載しておきます。
<%= javascript_include_tag src=“https://d3js.org/d3.v4.min.js” %>
<%= javascript_include_tag src=“http://techanjs.org/techan.min.js” %>
$ vim app/views/layouts/application.html.erb <!DOCTYPE html> <html> <head> <title>SampleD3</title> <%= csrf_meta_tags %> <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %> <%= javascript_include_tag src="https://d3js.org/d3.v4.min.js" %> <%= javascript_include_tag src="http://techanjs.org/techan.min.js" %> </head> <body> <%= yield %> </body> </html>
スタイルシートの記述
全ページで参照できるように「custom.scss」ファイルに記載しておきます。
$ vim app/assets/stylesheets/custom.scss path.candle { stroke: #000000; } path.candle.body { stroke-width: 0; } path.candle.up { fill: #FF0000; stroke: #FF0000; } path.candle.down { fill: #00AA00; stroke: #00AA00; } path.volume { fill: #696969; stroke-width: 1; } .sma path.line { fill: none; stroke-width: 1; } .ma25 path.line { stroke: #0000cd; }
アクションの記述
コントローラに必要なアクションを記載しておきます。indexは表示用のアクションなのでそのままですが、listはデータを渡す用のアクションにします。今回はサンプルなので、グラフ描画するようのデータは直書きしてしまいます。
$ vim app/controllers/candlestick_controller.rb class CandlestickController < ApplicationController def index end def list data = [ {Date: "2016-12-30", Open: "6829", High: "6913", Low: "6800", Close: "6878", Volume: "6708800"}, {Date: "2016-12-29", Open: "6935", High: "6960", Low: "6838", Close: "6838", Volume: "11400700"}, (中略) {Date: "2016-08-22", Open: "6078", High: "6109", Low: "6065", Close: "6100", Volume: "9130100"}, {Date: "2016-08-19", Open: "5969", High: "6060", Low: "5956", Close: "6026", Volume: "11944300"} ] render :json => data end end
D3.jsを利用するJavaScriptの記述
実際のD3.jsを利用するためのJavaScriptを「index.html.erb」に作成します。
$ vim app/views/candlestick/index.html.erb <script> // set the dimensions and margins of the graph var margin = {top: 20, right: 20, bottom: 30, left: 50}, width = 960 - margin.left - margin.right, height = 400 - margin.top - margin.bottom; // parse the date / time var parseDate = d3.timeParse("%Y-%m-%d"); // set the ranges var x = techan.scale.financetime() .range([0, width]); var y = d3.scaleLinear() .range([300, 0]); var yVolume = d3.scaleLinear() .range([height, 300]); // define the candlestick var candlestick = techan.plot.candlestick() .xScale(x) .yScale(y); // define the sma var sma = techan.plot.sma() .xScale(x) .yScale(y); // define the volume var volume = techan.plot.volume() .xScale(x) .yScale(yVolume); // append the svg obgect to the body of the page // appends a 'group' element to 'svg' // moves the 'group' element to the top left margin var svg = d3.select("body").append("svg") .attr("width", width + margin.left + margin.right) .attr("height", height + margin.top + margin.bottom) .append("g") .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); // Get the data d3.json('list', function(error, data) { var cAccessor = candlestick.accessor(); var vAccessor = volume.accessor(); // format the data & sort by date data = data.slice(0, 140).map(function(d) { return { date: parseDate(d.Date), open: +d.Open, high: +d.High, low: +d.Low, close: +d.Close, volume: +d.Volume }; }).sort(function(a, b) { return d3.ascending(cAccessor.d(a), cAccessor.d(b)); }); // Scale the range of the data x.domain(data.map(cAccessor.d)); y.domain(techan.scale.plot.ohlc(data, cAccessor).domain()); yVolume.domain(techan.scale.plot.volume(data, vAccessor.v).domain()); // Add the volume svg.append("g") .attr("class", "volume") .data([data]) .call(volume); // Add the candlestick svg.append("g") .attr("class", "candlestick") .data([data]) .call(candlestick); // Add the sma25 svg.append("g") .attr("class", "sma ma25") .datum(techan.indicator.sma().period(25)(data)) .call(sma); // Add the X Axis svg.append("g") .attr("transform", "translate(0," + height + ")") .call(d3.axisBottom(x)); // Add the Y Axis svg.append("g") .call(d3.axisLeft(y)); // Add the Volume-Y Axis svg.append("g") .call(d3.axisLeft(yVolume) .ticks(3) .tickFormat(d3.format(",.3s"))); }); </script>
実際のD3.js利用している部分については、前回と同様の記述をしています。まず、画面の大きさやマージンを指定し、利用することになるX軸とY軸用のrangeを指定、描画するためのグラフ種類を定義(今回はローソク足と25日線と出来高)、svg領域を作成してあげたら、データを取り込んだ後、domainを設定、最後にsvg領域にグラフとX軸、Y軸を追加しています。
書き方のルールさえ分かっていれば、サンプルも多数用意してくれていたので、簡単にグラフを描画できました。