カテゴリー
[Sass] sassだけで株価ローソク足チャートを描く方法
※ 当ページには【広告/PR】を含む場合があります。
2020/05/22
今回は軽量&簡単なローソク足チャートをSassのコーディングだけで描いてみようと言う野心的な試みです。
巷では
D3.js
Chart.js
これまでのわざわざフルスクラッチで...ましてやスタイルファイルだけでグラフを作ろうということ自体、かなりマイノリティーなお話になっています。
とは言え、jsスクリプトを使わず、html内のグラフを純粋なcssのだけで記述できることの最もメリットは、
クライアント側で描画時のJavascriptのレンダリング処理が不要になる
どうしてもチャート系のjsライブラリを使うと、グラフの処理にリソースが割かれて、挙動が重くなってしまう宿命にあります。
遅延ロードさせることでこれを回避することも可能ですが、今度は遅延ロードをさせるためのライブラリーやスクリプトの実装などに色々と頭を悩まさなくてはいけなくなります。
また、チャート操作用のjsライブラリーは使い方を覚えるまでにかかる学習コストがあり、なかなか思うようなチャートが描けるようになるまで時間もかかります。
このようにチャート系のjsライブラリーの利用には、高性能な分、色々とデメリットの面も考えさせられます。
他方、cssスタイルファイルだけでどうにかなるのなら、描画時間が短縮になり、遅延ロードのような煩雑になる仕組みを考えなくても済みます。
余程の凝りに凝ったアニメーションを行いたい訳でないのなら、cssでも簡単なアニメーションを装飾させることも可能です。
前置きはさておき、簡単なローソク足の株価チャートを具体的なコーディングと共に説明していきます。
描画用のデータ
以前、
この考え方にしたがって、とりあえず以下のように株価の日足データの1つだけ与えておきます。
// とある会社のある日の日足データ
$stock_data: [
// [日付, 始値, 高値, 低値, 終値]
['2020-05-20', 310, 321, 299, 314]
];
では、このデータからローソク足をひとつ描画できるまでをやってみます。
ローソク足
データ1つで実験
描画は
div
幅は
100%
200px
<div class="hiashi-chart">
<div class="hiashi-1"></div>
</div>
赤の四角で陽線、青で陰線を与えることにします。
まずは日足のデータを元に、手作業でローソク足を描画して雛形を作成します。
.hiashi-chart {
width: 100%;
height: 200px;
padding: 30px;
border: 2px solid black;
.hiashi-1 {
$rect_width: 20px;
$rect_hieght: 314px - 310px; // ① 終値 - 始値
$rect_color: red; // ② 陽線
$line_width: 1px;
$line_height: 321px - 299px; // ③ 高値 - 終値
$line_top_pos: 314px - 321px; // ④ 終値 - 高値
position: relative;
width: $rect_width;
height: $rect_hieght;
background-color: $rect_color;
&::after {
position: absolute;
left: ($rect_width + $line_width) / 2;
top: $line_top_pos;
content: '';
height: $line_height;
border-left: $line_width solid $rect_color;
}
}
}
これを描画すると以下です。
ローソク足一つだと、まだチャートへったくれもないのです。
ここからローソク足チャートを描画するためにコードを拡張していきましょう。
さて、コードの中身でもコメントで書き込んでいるように、データからローソクを描画する際に計算をするポイントが何個かあります。
①:
ローソクの高さ = (終値 - 始値)の絶対値
②:
陽線か陰線か = (終値 - 始値)での正負符号
③:
ヒゲの高さ = (高値 - 終値)の値
④:
ローソクのtopからみたヒゲの描画開始位置 = (終値 - 高値)の値。
今回は終値が基準(=ローソクのtop位置)だったが、
始値が基準の場合には(始値 - 高値)の値を計算する
主に以上のような点を考慮しながらデータをローソク足に読み取っていきます。
@mixin化
同じようなスタイルを使い回す場合には
@mixin
先ほどのソースコードで、
@mixin
@mixin generic_hiashi(
$hiashi-index,
$rect_width: 20px,
$rect_hieght: 0,
$rect_color: red,
$line_width: 1px,
$line_height: 0,
$line_top_pos: 0
) {
.hiashi-#{$hiashi-index} {
position: relative;
width: $rect_width;
height: $rect_hieght;
background-color: $rect_color;
&::after {
position: absolute;
left: ($rect_width + $line_width) / 2;
top: $line_top_pos;
content: '';
height: $line_height;
border-left: $line_width solid $rect_color;
}
}
}
.hiashi-chart {
width: 100%;
height: 200px;
padding: 30px;
border: 2px solid black;
@include generic_hiashi(1, 20px, 314px - 310px, red, 1px, 321px - 299px, 314px - 321px);
}
とできます。
こちらの方が、スタイルをスッキリした見通しの良い形式で管理できます。
データ読み込み後のパラメータ自動計算
先ほどのミクスインに株価のデータの配列がそのまま引数として渡せるように改良します。
@mixin generic_hiashi(
$hiashi-index,
$rect_width: 20px,
$line_width: 1px,
$hiashi_data: ['2000-01-01', 0, 0, 0, 0]
) {
.hiashi-#{$hiashi-index} {
position: relative;
width: $rect_width;
$diff: nth($hiashi_data, 5) - nth($hiashi_data, 2);
height: abs($diff * 1px);
$rect_color: red;
@if $diff < 0 {
$rect_color: blue;
}
background-color: $rect_color;
&::after {
position: absolute;
content: '';
left: ($rect_width - $line_width) / 2;
top: (max(nth($hiashi_data, 2), nth($hiashi_data, 5)) - nth($hiashi_data, 3)) * 1px;
height: (nth($hiashi_data, 3) - nth($hiashi_data, 4)) * 1px;
border-left: $line_width solid $rect_color;
}
}
}
.hiashi-chart {
width: 100%;
height: 300px;
padding: 30px;
border: 2px solid black;
@include generic_hiashi(1, 20px, 1px, ['2020-05-20', 310, 321, 299, 314]);
}
配列からローソク足の生成
上記までの内容でローソク足一つの描画を試しただけでした。
複数のローソク足をまとめて描画するには、日付で時間軸(x軸)上に、株価でy軸上にチャート要素に対して相対的な位置決めをする必要があります。
x軸の平行移動
日足データは日付を1つ変数として持っています。
ですが、型が
string
そこで数値型として扱うときに都合の良い
Epoch時間
例えば、
+ 2020-01-01 00:00:00(国際標準時) ==> 1577804400
+ 2000-01-01 00:00:00(国際標準時) ==> 946652400
+ 2020-01-01 00:00:00(国際標準時) ==> 1589986800
Epoch時間は国際標準時間換算ですので、実際の日本時間はここから+9時間された値となります。
日足の場合には、日付だけが判別できれば良いので、今回は時差を考慮せず国際標準時のまま利用します。
ミリ秒なしのEpoch時間で便利なのが、
1時間=3600
1日=86400
また、Epoch時間の換算は自前での換算関数実装がわりと複雑です。
予め日足データにEpoch時間を組み込んでおきます。
とりあえず10日分くらいの描画実験用データを与えておきましょう。
// とある会社のある日の日足データ
$stock_data: [
// [日付, Epoch時間(GMT), 始値, 高値, 低値, 終値]
['2020-05-20', 1589900400, 310, 321, 299, 314],
['2020-05-19', 1589814000, 305, 319, 301, 311],
['2020-05-18', 1589727600, 304, 325, 302, 312],
['2020-05-15', 1589468400, 310, 311, 297, 304],
['2020-05-14', 1589382000, 300, 309, 294, 298],
['2020-05-13', 1589295600, 299, 305, 292, 295],
['2020-05-12', 1589209200, 295, 301, 285, 290],
['2020-05-11', 1589122800, 291, 302, 286, 290],
['2020-05-08', 1588863600, 284, 300, 276, 280],
['2020-05-07', 1588777200, 285, 288, 273, 288],
];
とりあえずデータ配列は日付に対して降順で並べています。
このデータを元に時間軸で並行移動できるように再度scssコードにx軸座標を計算して返す補助的な関数を用意します。
@function configure-xaxis($source_array, $base_width: 100%) {
$first: nth(nth($source_array, 1), 2);
$last: nth(nth($source_array, length($source_array)), 2);
@return [$first, $last, $base_width , $base_width * 86400 / ($first - $last)];
}
@function epochtime-to-xpos($epoch_date, $x_pos_unit) {
$first: nth($x_pos_unit, 1);
$last: nth($x_pos_unit, 2);
$x_pos: ($last - $epoch_date) / ($last - $first) * nth($x_pos_unit, 3);
@return $x_pos;
}
深くは解説しませんが、
configure-xaxis
epochtime-to-xpos
y軸方向の補正
y軸方向にも、チャートの描画範囲に応じた座標を計算する関数が必要になります。
@function configure-yaxis($min_limit: 0, $max_limit: 100, $base_hight: 100%) {
@return [$min_limit, $max_limit, $base_hight, $base_hight / ($max_limit - $min_limit)];
}
@function currentprice-to-ypos($current_price, $y_pos_unit) {
$min: nth($y_pos_unit, 1);
$max: nth($y_pos_unit, 2);
$y_pos: ($max - $current_price) / ($max - $min) * nth($y_pos_unit, 3);
@return $y_pos;
}
これも先程のx軸で用いる補助関数と同じような考え方ですが、y軸方向の描画範囲(下限・上限)は手動で値を割り振るようにしています。
ミクスインの修正
それではx軸、y軸の補正関数を組み込んで、再度ミクスインを修正します。
@mixin generic_hiashi(
$hiashi-index,
$rect_width: 20px,
$line_width: 1px,
$hiashi_data: ['2000-01-01', 946652400, 0, 0, 0, 0],
$xaxis_config: [100, 0, 100px, 100%], // x軸方向の設定パラメータ
$yaxis_config: [0, 100, 300px, 1px] // y軸方向の設定パラメータ
) {
.hiashi-#{$hiashi-index} {
position: absolute;
left: epochtime-to-xpos(nth($hiashi_data, 2), $xaxis_config);
width: $rect_width;
top: currentprice-to-ypos(max(nth($hiashi_data, 3), nth($hiashi_data, 6)), $yaxis_config);
$diff: nth($hiashi_data, 6) - nth($hiashi_data, 3);
height: abs($diff * nth($yaxis_config, 4));
$rect_color: red;
@if $diff < 0 {
$rect_color: blue;
}
background-color: $rect_color;
&::after {
position: absolute;
content: '';
left: ($rect_width - $line_width) / 2;
top: (max(nth($hiashi_data, 3), nth($hiashi_data, 6)) - nth($hiashi_data, 4)) * nth($yaxis_config, 4);
height: (nth($hiashi_data, 4) - nth($hiashi_data, 5)) * nth($yaxis_config, 4);
border-left: $line_width solid $rect_color;
}
&::before {
position: absolute;
font-size: 10px;
content: nth($hiashi_data, 1);
left: 0;
top: 10px;
}
}
}
.hiashi-chart {
position: relative;
$chart_width: 600px;
$chart_height: 200px;
width: $chart_width;
height: $chart_height;
padding: 10px 40px;
border: 2px solid black;
$xaxis_configuration: configure-xaxis($stock_data, $chart_width);
$yaxis_configuration: configure-yaxis(270, 330, $chart_height);
$i: 1;
@each $item in $stock_data {
@include generic_hiashi($i, 20px, 1px, $item, $xaxis_configuration, $yaxis_configuration);
$i: $i + 1;
}
}
htmlのコードは以下のように変更です。
<div class="hiashi-chart">
<div class="hiashi-1"></div>
<div class="hiashi-2"></div>
<div class="hiashi-3"></div>
<div class="hiashi-4"></div>
<div class="hiashi-5"></div>
<div class="hiashi-6"></div>
<div class="hiashi-7"></div>
<div class="hiashi-8"></div>
<div class="hiashi-9"></div>
<div class="hiashi-10"></div>
</div>
チャートは以下のようになりました。
実用上はまだまだ機能を盛り込んでいく必要がありますが、最低限のローソク足チャートが描画できました。
まとめ
今回はローソク足チャートで日足の描画するところまでを解説しました。
まだ軸にチックで刻みをいれたり、ラベルをいれたり、マウスでホバー時にイベントを行ったり...
ここからの応用して実用的なチャートにするにはまだまだ工夫が必要になります。
html側も手動でclass名を入力して各要素にスタイリングしています。
css側で
div:nth-child()
また気が向いたら、もっとローソク足チャートらしいものを作成して、このブログで紹介するかもしれません。
まだまだ改良の余地がありますが、この記事に載せたコードはいくらでも改変していただいて構いません。
お手元でカスタマイズしてオリジナルの株価チャートを自作しても面白いかもしれません。
記事を書いた人
ナンデモ系エンジニア
主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。
カテゴリー