JavaScriptでローソク足チャートの作成

#概要
株価の推移を可視化するために用いられる、ローソク足チャートをJavaScriptを用いて描画してみます。完成物は、以下の画像のようなものになります。
![Screen Shot 2018-08-27 at 21.42.20.png](https://qiita-image-store.s3.amazonaws.com/0/283226/8623fac9-8576-63dd-63fe-622dac2e746a.png)
ユーザが**①銘柄コード**と**②チャート描画期間**を入力すると、チャートが描画されます。
チャート領域内には、**①株価の動きを表すローソク足**、**②三本の移動平均線グラフ**、**③出来高を表す棒グラフ**、の三種類の情報が表示されます。
#今回用いるツール
主に二つのツールを用います。
##IEX API
株価や出来高などの金融情報は、[IEX API](https://iextrading.com/developer/docs/)から取得します。
このAPIからはアメリカの上場企業の株価が無料で取得できます。キーだとかアカウントだとかは必要ありません。国内株が取得できないところが難点ですが、使いやすいので我慢します。

リクエストはHTTPのGET通信で行います。リクエストのURLの例は、`https://api.iextrading.com/1.0/stock/aapl/chart/5y`のようなものとなります。
`/aapl`の部分に銘柄コードを、`/5y`の部分に取得したい期間を記述します。
上の例はアップルの５年分のヒストリカル情報を要求するものですが、これに対するレスポンスは、

```json
[
  {
      "date":"2013-08-27",
      "open":65.1405,
      "high":65.7304,
      "low":63.6101,
      "close":63.9096,
      "volume":105930335,
      "unadjustedVolume":15132905,
      "change":-1.881,
      "changePercent":-2.859,
      "vwap":64.5862,
      "label":"Aug 27, 13",
      "changeOverTime":0
  },
 ...
]
```
のようなJSON形式のものになります。
##Google Charts
チャートを描画するためのツールです。後述するように、HTMLのscriptタグで読み込んで、JavaScriptで使うことができます。公式ドキュメントは[こちら](https://developers.google.com/chart/)。様々な種類のチャートを作成することができますが、今回はローソク足、線グラフ、棒グラフの三つを用います。
#ページのデザイン(HTML)
まずは簡単にwebページのデザインをします。

```html:chart.html
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <title>Chart</title>
<!--- デザインに関する規定はこれしかないので、cssファイルではなくstyleタグに記述 --->
<style>
input{
    width: 140px;
    margin: 10px;
}
select{
    margin: 10px;
}
</style>
</head>
<body>
<!--- 銘柄コードを受け付けるボックス --->
    <input type = "text" maxlength = "4" id='input'><button id='btn'>Get Info</button>
<!--- 描画期間を選ばせるプルダウンメニュー --->
    <select id="span">
        <option value="6m" selected>
            6m
        </option>
        <option value="1y">
            1y
        </option>
        <option value="2y">
            2y
        </option>
        <option value="5y">
            5y
        </option>
    </select>
<!--- ローソク足及び移動平均線グラフを配置 --->
    <div id='appendMain'></div>
<!--- 出来高の棒グラフを配置 --->
    <div id='appendVolume'></div>
<script src="http://code.jquery.com/jquery-1.10.1.min.js"></script>
<!--- ここでGoogle Chartの読み込み --->
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script src="chart.js"></script>
</body>
</html>

```
最後の方でGoogle Chartを読み込むことを忘れないでください。
#チャートの描画(JavaScript)
いよいよ具体的な処理を記述していきます。jsファイルを用意し、以下の記述を書き加えていきます。
###Google Chartの呼び出し

```javascript:chart.js
google.charts.load('current', {'packages':['corechart']});
```
チャート描画の処理を書く前に、このように記述をしてGoogle Chartを呼び出します。`'current'`は最新バージョンであることを、`'corechart'`は、今回用いる機能が含まれているパッケージを表します。
###ユーザの入力

```javascript:chart.js
$('#btn').click(function(){
    var code = $('#input').val()
    var span = $('#span').val()
    getInfo(code, span, mainChart);
})
```
ユーザがボタンをクリックした際に行われる処理です。変数codeに銘柄コードを、変数spanに描画期間を入れて、これらとコールバック関数「mainChart」を引数にして、getInfo関数を呼び出します。

###APIからの情報取得

```javascript:chart.js
function getInfo(code, span, callback){
    $.ajax({
        url : 'https://api.iextrading.com/1.0/stock/' + code + '/chart/' + span,
        type : 'GET',       
        async : true,        
        cashe : false,     
        dataType : 'json',  
        contentType : 'application/json' 
    }).done(function(result){
        callback(result);
    }).fail(function(result){
        alert('Failed to load the information');
        console.log(result)
    });  
}
```
urlの中に、ユーザが入力した銘柄コードと描画期間を組み込み、通信を行います。正常に情報が取得できた場合は、引数として受け取ったmainChartをコールバック関数として実行します。

###ローソク足と移動平均線チャートの作成

```javascript:chart.js
function mainChart(result){
    //チャートに描画するための最終的なデータを入れる
    var chartData = new google.visualization.DataTable();
        //日付ようにString型のカラムを一つ、チャート描画用に数値型のカラムを７つ作成
        chartData.addColumn('string');
        for(var x = 0;x < 7; x++){
            chartData.addColumn('number');
        }
        //いちいち書くのが面倒なので、取得した情報の長さを配列に入れる
        var length = result.length;
        //描画用のデータを一時的に入れる
        var insertingData = new Array(length);
        //平均を出すための割り算の分母
        var divide = 0;
        //二次元配列aveに、平均線の日数と平均値を入れる
        var ave = new Array();
        //５日平均線用
        ave[0] = new Array();
        //25日平均線用
        ave[1] = new Array();
        //50日平均線用
        ave[2] = new Array();
        //平均線の計算に用いる
        var temp = 0;
        //５日移動平均線の算出
        //基準日より５日前までのデータを足し合わせ、平均値を出す
        for(var m = 0; m < length - 4; m++){
            for(var n = 0; n < 5; n++){
                if(result[m+n].close != ''){
                    temp = temp + parseFloat(result[m+n].close);
                    divide++;
                }
            }
            ave[0][m] = temp / divide;
            temp = 0;
            divide = 0;
        }
        //2５日移動平均線の算出
        //上と同様の処理
        for(var m = 0; m < length - 24; m++){
            for(var n = 0; n < 25; n++){
                if(result[m+n].close != ''){
                    temp = temp + parseFloat(result[m+n].close);
                    divide++
                }
            }
            ave[1][m] = temp / divide;
            temp = 0;
            divide = 0;
        }
        //５0日移動平均線の算出
        //上と同様の処理
        for(var m = 0; m < length - 49; m++){
            for(var n = 0; n < 49; n++){
                if(result[m+n].close != ''){
                    temp = temp + parseFloat(result[m+n].close);
                    divide++
                }
            }
            ave[2][m] = temp / divide;
            temp = 0;
            divide = 0;
        }
        //for文をまとめるため、出来高棒グラフの処理もここで行う
        //出来高を保持する配列
        var volume = new Array();
        //チャートの日付を保持する配列
        var dates = new Array();
        for(var s = 0; s < length; s++){
            if(result[s].volume != ''){
                volume[s] = result[s].volume;
                dates[s] = String(result[s].date);
            }
        }
        //配列insertingDataの中に、[安値、始値、高値、終値、５日移動平均線、２５日移動平均線、５０日移動平均線]の形で値を入れ込む
        for(var a = 0; a < length; a++){
            insertingData[a] = [dates[a],parseFloat(result[a].low),parseFloat(result[a].open),parseFloat(result[a].close),parseFloat(result[a].high),ave[0][a],ave[1][a],ave[2][a]]
        }
        //チャート描画用の配列の中に、insertingDataの値を入れ込む
        //最古の50日分のデータまでは移動平均線のデータが揃っていないので、取り除く
        for (var i = insertingData.length - 50; i > 0; i--){
            chartData.addRow(insertingData[i]);
        }
        //チャートの見た目に関する記述、詳細は公式ドキュメントをご覧になってください
        var options = {
            chartArea:{left:80,top:10,right:80,bottom:10},
            colors: ['#003A76'],
            legend: {
                position: 'none',
            },
            vAxis:{
                viewWindowMode:'maximized'
            },
            hAxis: {
                format: 'yy/MM/dd',
                direction: -1,
            },
            bar: { 
                groupWidth: '100%' 
            },
            width: 1200,
            height: 400,
            lineWidth: 2,
            curveType: 'function',
            //チャートのタイプとして、ローソク足を指定
            seriesType: "candlesticks",  
            //ローソク足だでなく、線グラフも三種類表示することを記述
            series: {
                1:{
                    type: "line",
                    color: 'green',
                },
                2:{
                    type: "line",
                    color: 'red',                
                },
                3:{
                    type: "line",
                    color: 'orange',                
                },
            } 
        };
        //描画の処理
        var chart = new google.visualization.ComboChart(document.getElementById('appendMain'));
        chart.draw(chartData, options);
        //出来高棒グラフを作成する関数を呼び出し
        volumeChart(volume, dates, length);
}
```

###出来高棒グラフの作成

```javascript:chart.js
function volumeChart(volume, dates, length){
    var chartData = new google.visualization.DataTable();
    //出来高の値と日付のためのカラムを作成
    chartData.addColumn('string');
    chartData.addColumn('number');
    var insertingData = new Array();
    //配列insertingDataの中に、[日付、出来高]の形式でデータを入れ込む
    for(var a = 0; a < length; a++){
        insertingData[a] = [dates[a],parseInt(volume[a])]
    }
    //insertingDataの値をチャート描画用の変数に入れ込む
    for (var i = insertingData.length - 50; i > 0; i--){
        chartData.addRow(insertingData[i]);
    }
    //ローソク足の時と同じように、見た目の設定をする
    var options = {
        chartArea:{left:80,top:10,right:80,bottom:80},
        colors: ['#003A76'],
        legend: {
            position: 'none',
        },
        bar: { 
            groupWidth: '100%' 
        },
        hAxis: {direction: -1},
        width: 1200,
        vAxis:{
            viewWindowMode:'maximized'
        },
    }
    var chart = new google.visualization.ColumnChart(document.getElementById('appendVolume'));
    chart.draw(chartData, options);
}
```


#完成物
上のコードを書き終わると、成果物が完成します。
以下の画像のように、それっぽいローソク足チャートができています。
![Screen Shot 2018-08-27 at 21.42.20.png](https://qiita-image-store.s3.amazonaws.com/0/283226/6060f6a6-4936-14b8-aa36-f4ceddfb7ccc.png)