今回は、セントラル短資FX データダウンロードからCSVデータを取得して、日足チャートを表示する方法を紹介します。
※公開を目的としたアプリから直接データを取得する場合、予めデータ提供サイトに利用許可など確認する必要があります。
XMLHttpRequest()を利用してCSVデータを取得します。
CSVデータはShift-JISなのでUTF-8に文字コードを変換する必要がありますが、ヘッダー部の文字化けが発生するだけなので、変換せずに処理を行っています。
index.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
<!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover"> <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'"> <script src="components/loader.js"></script> <script src="lib/onsenui/js/onsenui.min.js"></script> <script src="js/moment.min.js"></script> <script src="js/d3.min.js"></script> <script src="js/d3chart.js"></script> <script src="js/app.js"></script> <link rel="stylesheet" href="components/loader.css"> <link rel="stylesheet" href="lib/onsenui/css/onsenui.css"> <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css"> <link rel="stylesheet" href="css/style.css"> </head> <body> <ons-page> <ons-toolbar> <div id="title" class="center">D3.js</div> </ons-toolbar> <ons-list> <ons-list-item> <div class="segment" style="width: 320px; margin: 0 auto;"> <div class="segment__item"> <input type="radio" class="segment__input" name="pear" onclick="getCsvData('USDJPY')" checked> <div class="segment__button">USDJPY</div> </div> <div class="segment__item"> <input type="radio" class="segment__input" name="pear" onclick="getCsvData('EURJPY')" > <div class="segment__button">EURJPY</div> </div> <div class="segment__item"> <input type="radio" class="segment__input" name="pear" onclick="getCsvData('EURUSD')" > <div class="segment__button">EURUSD</div> </div> <div class="segment__item"> <input type="radio" class="segment__input" name="pear" onclick="getCsvData('GBPJPY')" > <div class="segment__button">GBPJPY</div> </div> <div class="segment__item"> <input type="radio" class="segment__input" name="pear" onclick="getCsvData('GBPUSD')" > <div class="segment__button">GBPUSD</div> </div> </div> </ons-list-item> </ons-list> <div id="chart"></div> </ons-page> </body>> </html> |
style.css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
#chart { width: 100%; height: 240px; } #d3-chart { background-color: #000; } .axis text { font-size: 9px; color: #fff; } .axis path, .axis line { fill: none; stroke: #ccc; stroke-width: 1px; } .tick line { opacity: 0.3; stroke-width: 1px; } /* candlestick */ .candlestick-yosen { fill: #f00; stroke: #f00; stroke-width: 1px; } .candlestick-insen { fill: #0ff; stroke: #0ff; stroke-width: 1px; } |
app.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
"use strict"; var data = []; // 日足データ var getCsvData = function (pear) { var index = ""; var req = new XMLHttpRequest(); switch (pear) { case "USDJPY": index = "01"; break; case "EURJPY": index = "02"; break; case "EURUSD": index = "03"; break; case "GBPJPY": index = "04"; break; case "GBPUSD": index = "05"; break; default: } if (index == "") return; req.open("GET","https://info.ctfx.jp/service/market/csv/" + index + "_" + pear + "_D.csv"); req.onload = function () { var csv = req.responseText; var row = csv.split("\n"); var col = []; var date = null; var i = 0; // 日足データ初期化 data = []; for (i = row.length - 1; i > 0; i--) { if (row[i].length > 0) { // カンマで分割する col = row[i].match(/[^,]+/g); // 日付をYYYY/MM/DDからYYYYMMDDに変換する date = moment(col[1], "YYYY/MM/DD").format("YYYYMMDD"); // 日足データ追加 data.push([date, Number(col[2]), Number(col[3]), Number(col[4]), Number(col[5])]); } } if (data.length > 0) { document.getElementById("title").innerHTML = "D3.js " + pear + " 日足"; showChart(pear); } }; req.send(null); }; var showChart = function (pear) { var month = data.slice(data.length - 30); window.fn.chart.createChart("chart", pear, month); }; ons.ready(function () { getCsvData("USDJPY"); }); |
d3chart.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
"use strict"; //************************************************************ // module: d3chart.js // author: otak-lab // use: d3.min.js //************************************************************ if (!window.hasOwnProperty("fn")) { window.fn = {}; } window.fn.chart = {}; //************************************************************ // create candlestick chart //************************************************************ window.fn.chart.createChart = function (id, pear, data) { var elem = document.getElementById(id); if (!elem) return; if (data.length == 0) return; // margin var margin = { top: 10, right: 45, bottom: 25, left: 10 }; // width, height var w = elem.clientWidth - (margin.left + margin.right); var h = elem.clientHeight - (margin.top + margin.bottom); // min, max var min = Math.min.apply(null, data.map(function (d) { return Math.min(d[2], d[3]); })); var max = Math.max.apply(null, data.map(function (d) { return Math.max(d[2], d[3]); })); // y var y = d3.scaleLinear() .domain([min, max]) .nice() .range([h, 0]); // x var x = d3.scaleBand() .domain(data.map(function (d) { return d[0]; })) .range([0, w]); // adjust line x positon var pos = (x(data[1][0]) - x(data[0][0])) / 2; // axis var yAxis = d3.axisRight(y) .tickSizeInner(-w) .tickSizeOuter(0) .tickPadding(4) .tickFormat(function (d) { return (pear.search(/JPY/) == -1) ? d3.format(".5f")(d) : d3.format(".3f")(d); }) .ticks(7); var yRange = yAxis.scale().domain(); var xAxis = d3.axisBottom(x) .tickValues(x.domain()) .tickSizeInner(-h) .tickSizeOuter(0) .tickPadding(8) .tickFormat(function (d, i) { var result = Number(d.substr(6, 2)).toString(); if ((i % 3) == 0) { result = Number(d.substr(4, 2)).toString() + "/" + result; } else { result = null; } return result; }); var xRange = xAxis.scale().domain(); // remove chart d3.select("#d3-chart").remove(); // create svg var svg = d3.select(elem) .append("svg") .attr("id", "d3-chart") .attr("width", elem.clientWidth.toString()) .attr("height", elem.clientHeight.toString()) .append("g") .attr("transform", "translate(" + margin.left.toString() + ", " + margin.top.toString() + ")"); // create x svg.append("g") .attr("class", "axis") .attr("transform", "translate(0, " + h.toString() + ")") .call(xAxis); // create y svg.append("g") .attr("class", "axis") .attr("transform", "translate(" + w.toString() + ", 0)") .call(yAxis); // candlestick body var cbw = Math.abs(x(xRange[1]) - x(xRange[0])) - 3; var cb = svg.selectAll("rect.b") .data(data) .enter() .append("rect"); cb.attr("class", function (d) { var cl = "candlestick-yosen"; if (d[1] > d[4]) { cl = "candlestick-insen"; } return cl; }) .attr("x", function (d) { return (x(d[0]) + pos - (cbw / 2)); }) .attr("y", function (d) { return y((d[1] > d[4]) ? d[1] : d[4]); }) .attr("width", cbw) .attr("height", function (d) { var top = (d[1] > d[4]) ? d[1] : d[4]; var bottom = (d[1] > d[4]) ? d[4] : d[1]; var diff = Math.abs(y(top) - y(bottom)); if (diff == 0) diff = 0.1; return diff; }); // candlestick shadow var csw = 0.5; var cs = svg.selectAll("rect.s") .data(data) .enter() .append("rect"); cs.attr("class", function (d) { var cl = "candlestick-yosen"; if (d[1] > d[4]) { cl = "candlestick-insen"; } return cl; }) .attr("x", function (d) { return (x(d[0]) + pos - (csw / 2)); }) .attr("y", function (d) { return y(d[2]); }) .attr("width", csw) .attr("height", function (d) { return Math.abs(y(d[2]) - y(d[3])); }); }; |
各通貨のセグメントをタップすると、日足のCSVデータを取得してチャートを表示します。
FX チャートリーディング マスターブック ~為替のプロが実践する本当に勝てるワザを大公開! 新品価格 |