taikoothong/templates/tw_stock.html.hbs

418 lines
11 KiB
Handlebars
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!--
以下內容屬於程式碼一部分
This code is under MIT License
(c) 2023 Tan, Kian-ting
==========8964路路线资讯==================================
起讫站:程式码→墙内
票价Free<五毛人民币)
時刻:机动发车,单向行驶
停靠站:程式码→民主化→六四天安门→自由门下载→毋忘六四→刘晓波→
台湾独立→民运→西藏独立→新疆独立→港独→九评共产党→法轮功→
Tiananmen Massacre→Free Tibet→ 占领中环→民主→真普选→
南方街头运动→新公民运动→东突厥斯坦→湖南共和国→上访→ 大纪元→胡耀邦
→赵紫阳→Tank Man→北京之春→达赖喇嘛→六四真相→无界下载→通商宽衣→
躺平就是正义→习包子→梁家河小学博士→清零宗→习炀帝→庆丰大帝→
独裁国贼→新疆集中营→光复香港时代革命→祈翠→南蒙古独立→香港独立→
Free Hong Kong→天安门屠杀→中国言论钳制→中共文字狱→
如何润到墙外→中国青年失业率真相→历史的伤口→白纸革命→四通桥事件→
墙内
-->
<head>
<title>台股通</title>
<style type="text/css">
#stock-table{
border-collapse: collapse;
}
#stock-table th {
border: 1px solid red;
}
#stock-table td {
text-align: right;
padding: 1em 0.6em;
border: 1px solid red;
}
#css-table {
display:table;
}
.css-tr {
display: table-row;
}
.css-td {
display: table-cell;
}
</style>
<style>
body {
font: 10px sans-serif;
}
text {
fill: #000;
font-size: 14px;
}
button {
position: absolute;
right: 20px;
top: 440px;
display: none;
}
path.candle {
stroke: #000000;
}
path.candle.body {
stroke-width: 0;
}
path.candle.up {
fill: #dc3526;
stroke: #dc3526;
}
path.candle.down {
fill: #007d30;
stroke: #007d30;
}
path.volume.up {
fill: #dc3526;
stroke: #dc3526;
}
path.volume.equal {
fill: #dc3526;
stroke: #dc3526;
}
path.volume.down {
fill: #007d30;
stroke: #007d30;
}
.indicator.ma-0{
stroke:blue;
}
.text.ma-0{
fill:blue;
}
.indicator.ma-1{
stroke:orange;
}
.text.ma-1{
fill:orange;
}
.indicator.ma-2{
stroke:green;
}
.text.ma-2{
fill:green;
}
</style>
</head>
<html>
<body>
<h2 id="stock_id">{{main.stock_id.0}}</h2>
(<a href="{{main.stock_id.0}}/json">JSON</a>)
<div id="css-table">
<div class="css-tr">
<div class="css-td"><table id="stock-table">
<tr id="title-of-table">
<th>日期</th>
<th>開盤</th>
<th>收盤</th>
<th>最高</th>
<th>最低</th>
<th>成交量</th>
</tr>
{{#with main}}
{{#each date}}
<tr id={{this}}>
<td class="date">{{this}}</td>
<td class="open">{{lookup ../open @index}}</td>
<td class="close">{{lookup ../close @index}}</td>
<td class="high">{{lookup ../high @index}}</td>
<td class="low">{{lookup ../low @index}}</td>
<td class="volume">{{lookup ../volume @index}}</td>
</tr>
{{/each}}{{/with}}
</table></div><div>
<h3 id="chart-title"></h3>
<div class="css-td">
<input type="radio" name="range" value="5d">5日<br>
<input type="radio" name="range" value="30d">30日<br>
<input type="radio" name="range" value="ytd" checked="checked">今年迄今<br>
<svg id="chart"></svg></div>
<div class="css-td"><h3 id="chart-title">Yahoo 股市新聞</h3>
<div id="news_content">{{#each news}}
<div><div class="news-title"><a href="{{this.link}}">{{this.title}}</a></div>
<div class="news-date">{{this.date}}</div>
<div class="news-summary">{{this.summary}}……</div>
{{/each}}</div></div>
</div></div>
<script src="https://d3js.org/d3.v4.min.js"></script>
<script src="https://techanjs.org/techan.min.js"></script>
<script>
var margin = {top: 20, right: 50, bottom: 30, left: 50},
width = 960 - margin.left - margin.right,
height = 800 - margin.top - margin.bottom;
var parseDate = d3.timeParse("%d-%b-%y");
var x = techan.scale.financetime()
.range([0, width]);
var y_height = height * 0.7;
var y = d3.scaleLinear()
.range([y_height, 0]);
var candlestick = techan.plot.candlestick()
.xScale(x)
.yScale(y);
var y_volume = d3.scaleLinear()
.range([y(0), y(0.3)]);
var volume = techan.plot.volume()
.accessor(candlestick.accessor()) // Set the accessor to a ohlc accessor so we get highlighted bars
.xScale(x)
.yScale(y_volume);
var volume_axis = d3.axisLeft(y_volume)
.ticks(5)
.tickFormat(d3.format(",.3s"));
var volume_accessor = volume.accessor();
var sma0 = techan.plot.sma()
.xScale(x)
.yScale(y);
var sma1 = techan.plot.sma()
.xScale(x)
.yScale(y);
var sma2 = techan.plot.sma()
.xScale(x)
.yScale(y);
var xAxis = d3.axisBottom()
.scale(x)
.tickFormat(d3.timeFormat('%y-%m-%d'));
var yAxis = d3.axisLeft()
.scale(y);
var svg = d3.select('#chart')
.attr("width", width + margin.left + margin.right)
.attr("height", height + margin.top + margin.bottom)
.append("g")
.attr("transform", "translate(" + margin.left + "," + margin.top + ")");
var data_by_date = [];
d3.json(`{{main.stock_id.0}}/json`, function(d) {
console.log(d);
var data_by_date = [];
var parseDate = d3.timeParse("%Y-%m-%d");
for (var i=0;i<d["close"].length;i++){
data_by_date.push({
date: parseDate(d["date"][i]),
open: +d["open"][i],
high: +d["high"][i],
low: +d["low"][i],
close: +d["close"][i],
volume: parseInt(d["volume"][i].replace(/,/g, "")),
});};
console.log('dataGet', data_by_date);
var accessor = candlestick.accessor();
data_by_date = data_by_date.sort(function(a, b) { return d3.ascending(accessor.d(a), accessor.d(b)); });
svg.append("g")
.attr("class", "candlestick");
svg.append("g")
.attr("class", "volume")
.attr("transform", "translate(0," + height * 0.21 +")")
svg.append("g")
.attr("class", "x axis")
.attr("transform", "translate(0," + height * 0.7 + ")")
.append("text")
.text("日期")
.attr("transform", "translate(" + width + ", 20)");
svg.append("g")
.attr("class", "volume axis")
.attr("transform", "translate(0, " + height * 0.21 + ")")
.append("text")
.text("成交量")
.attr("transform", "rotate(-90) translate(-"+ height * 0.50 +", 10)")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
svg.append("g")
.attr("class", "y axis")
.append("text")
.attr("y", 6)
.attr("dy", ".71em")
.style("text-anchor", "end")
.text("股價NT$)")
.attr("transform", "translate(10, 0) rotate(-90)");
svg.append("g")
.attr("class", "indicator sma ma-0")
.attr("fill", "transparent");
svg.append("g")
.attr("class", "indicator sma ma-1")
.attr("fill", "transparent");
svg.append("g")
.attr("class", "indicator sma ma-2")
.attr("fill", "transparent");
// Data to display initially
d3.select("#chart-title").text("今年迄今");
draw(data_by_date);
// Only want this button to be active if the data has loaded
// d3.select("input").on("click", function() { draw(data_by_date); }).style("display", "inline");
d3.selectAll('input[name="range"]').on("change", function(){
if (this.value == "ytd"){
draw(data_by_date);
d3.select("#chart-title").text("今年迄今");
}
else if(this.value == "30d"){
draw(data_by_date.slice(data_by_date.length-30, data_by_date.length-1));
d3.select("#chart-title").text("30日");
}
else{
draw(data_by_date.slice(data_by_date.length-5, data_by_date.length-1));
d3.select("#chart-title").text("5日");
};
});
} );
function draw(data) {
x.domain(data.map(candlestick.accessor().d));
y.domain(techan.scale.plot.ohlc(data, candlestick.accessor()).domain());
y_volume.domain(techan.scale.plot.volume(data).domain());
svg.selectAll("g.candlestick").datum(data).call(candlestick);
svg.select("g.volume").datum(data).call(volume);
svg.select("g.volume.axis").call(volume_axis);
svg.selectAll("g.x.axis").call(xAxis);
svg.selectAll("g.y.axis").call(yAxis);
let sma0range = 5;
let sma1range = 20;
let sma2range = 60;
svg.select("g.sma.ma-0").datum(techan.indicator.sma().period(sma0range)(data)).call(sma0);
svg.select("g.sma.ma-1").datum(techan.indicator.sma().period(sma1range)(data)).call(sma1);
svg.select("g.sma.ma-2").datum(techan.indicator.sma().period(sma2range)(data)).call(sma2);
svg.select("g.sma.ma-0 g path").attr("id", "sma-0");
svg.select("g.sma.ma-1 g path").attr("id", "sma-1");
svg.select("g.sma.ma-2 g path").attr("id", "sma-2");
svg.append("text")
.attr("x", "1")
.attr("y", "1")
.append("textPath")
.attr("xlink:href", "#sma-0")
.attr("class", "ma-0 text")
.text("MA" + sma0range);
svg.append("text")
.attr("x", "1")
.attr("y", "1")
.append("textPath")
.attr("xlink:href", "#sma-1")
.attr("class", "ma-1 text")
.text("MA" + sma1range);
svg.append("text")
.attr("x", "1")
.attr("y", "1")
.append("textPath")
.attr("xlink:href", "#sma-2")
.attr("class", "ma-2 text")
.text("MA" + sma2range);
d3.selectAll("g.y .tick")
.append("line")
.attr("class", "gridline")
.attr("z-index", -100)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("stroke", "rgb(210, 210, 210)"); // line color
d3.selectAll("g.volume .tick")
.append("line")
.attr("class", "gridline")
.attr("z-index", -100)
.attr("x1", 0)
.attr("y1", 0)
.attr("x2", width)
.attr("y2", 0)
.attr("stroke", "rgb(210, 210, 210)"); // line color
}
</script>
</html>