Pythonのbokehで拡大縮小やドラッグができるローソク足のチャートを作る

スポンサーリンク

mplfinanceはとても手軽にローソク足のチャートが作成できるので普段はそれで問題ないのですが、bokehは、年間などで部分的に値動きやインジゲーターなどの状態を確認したい時などに、チャートを拡大縮小やドラッグと便利です。

bokehはmplfinanceよりチャートの種類が豊富で、以下のページにサンプルがあります。

Gallery
See the sections below for examples of using Bokeh in different ways. Server App Examples, Notebook Examples, Standalone Examples. Server App Examples: The exam...

今回はローソク足のチャートの作成方法を紹介します。

スポンサーリンク

はじめに

インストール

bokehは標準パッケージではありません。インストールが必要です。

pip install bokeh

インポート

インポートは公式サイトに従って、別名にしています。

from math import pi

from bokeh.plotting import figure, output_file, show
from bokeh.sampledata.stocks import MSFT

データについて

以下のような配列のデータを用意しています。画像は5分足ですが日足も用意しました。
dateカラムはpd.to_datetimeで変換していますが、インデックスではありません。注意してください。

サンプルデータ

基本

用意した日足データを50件ほど切り取って試しました。以下の感じですね。

df = df_master[50:100]

日足かつ50件のローソク足であれば、参考サイトの通りで表示できます。

inc = df.close > df.open
dec = df.open > df.close
w = 12*60*60*1000 # half day in ms

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"

p = figure(x_axis_type="datetime", tools=TOOLS, plot_width=1000, title = "USD/JPY Candlestick Daily bar")
p.xaxis.major_label_orientation = pi/4
p.grid.grid_line_alpha=0.3

p.segment(df.date, df.high, df.date, df.low, color="black")
p.vbar(df.date[inc], w, df.open[inc], df.close[inc], fill_color="#D5E1DD", line_color="black")
p.vbar(df.date[dec], w, df.open[dec], df.close[dec], fill_color="#F2583E", line_color="black")

output_file("candlestick.html", title="candlestick.py example")

show(p)  # open a browser

HTML版:bokeh_candlestick_example_Daily_bar

しかし、よく見ていただくとわかるのですが、問題があります。

  • 休日が歯抜けになる。1分足とかだとさらに酷いことになります。
  • 50件以上だとデザインが崩れる。

それらを改修して汎用性を持たせました。

以下を参考にしました。

ndepaola/bokeh-candlestick
Simple and responsive candlestick chart in Python with Bokeh - ndepaola/bokeh-candlestick

改修バージョン

bokehはローソク足を作るライブラリではないので、汎用性があり、対応次第って感じです。
悪くいうと無理やり作っている感があります。

改修内容や機能についての説明はソースの中に記載しました。

from bokeh.plotting import figure, output_file, show

# データフレームのマスクを設定
inc = df.close > df.open
dec = ~inc

# ローソク足の幅は固定
w = 0.5

TOOLS = "pan,wheel_zoom,box_zoom,reset,save"

# 日時表示用のフォーマットを設定(日足と分足に分岐
xaxis_dt_format = '%d %b %Y'
if df.iloc[0]['date'].second > 0:
    xaxis_dt_format = '%d %b %Y %H:%M:%S'

# チャートの設定
p = figure(
    x_axis_type="linear", # datetimeでは歯抜けになる。
    tools=TOOLS, 
    plot_width=1000, # チャートの幅
    title = "USD/JPY Candlestick Daily bar" # タイトルは任意に
)

p.xaxis.major_label_orientation = pi/4 # 日付を斜めに表示
p.grid.grid_line_alpha=0.3 # グリッドを薄く

# 以下のX軸を日付ではなくindexを設定するように変更
p.segment(df.index, df.high, df.index, df.low, color="black") # 高値と安値のラインを作成
p.vbar(df.index[inc], w, df.open[inc], df.close[inc], fill_color="#D5E1DD", line_color="black") # 陽線を作成
p.vbar(df.index[dec], w, df.open[dec], df.close[dec], fill_color="#F2583E", line_color="black") # 陰線を作成

# indexでラベルしたものを日付に上書き
p.xaxis.major_label_overrides = {
#     i + 50: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
    i: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
}
    
output_file("candlestick.html", title="candlestick.py example")

show(p)  # open a browser

bokeh ローソク足チャートのサンプル 5分足

HTML版:bokeh_candlestick_example_5_mins_bar

応用(チャートのカスタマイズ)

やっと応用に入れます。ここからは簡単でした。

各種ツール(tools)

bokehはチャートを拡大縮小やドラッグなどの機能をtoolsに設定します。
主な機能は以下の通り。

  • pan:水平・垂直移動
  • wheel_zoom:マウスのホイールによる拡大縮小
  • box_zoom:マウスのドラッグによる拡大縮小
  • box_select:マウスのドラッグでチャートを選択
  • crosshair:マウスの位置を十字の罫線で示す
  • reset:チャートを初期状態に戻す
  • save:チャートを画像で保存する

その他の機能は以下の公式サイトを参照してください。

Configuring plot tools
Bokeh comes with a number of interactive tools that you can use to report information, to change plot parameters such as zoom level or range extents, or to add,...

色の指定

16進数での指定も可能ですが、以下の色名で指定することが可能です。

公式サイトにカラーチャートがありましたので、そこで色を見つけることができます。

bokeh.colors
Provide classes for representing RGB(A) and HSL(A) colors, as well as define common named colors. bokeh.colors.Color: Provide a base class for representing colo...

色のセットをパレットで指定することもできます。

その場合、予めインポートが必要になります。

from bokeh.palettes import Spectral

palette=Spectral[6]

パレットの種類も公式サイトにカラーチャートがあります。

例えば、上記のパレットのSpectralは、公式サイトに3〜11のセットがありますので配列として指定します。

bokeh.palettes
Provide a collection of palettes for color mapping. In the context of Bokeh, a palette is a simple plain Python list of (hex) RGB color strings. For example the...

凡例の位置

グラフ内で位置を指定する

p.legend.location = "top_left"

以下を指定できます。

  • top_right
  • top_left
  • bottom_left
  • bottom_right

グラフの外に描画する

p.add_layout(p.legend[0], "left")

以下を指定できます。

  • left(枠の左外)
  • right(枠の右外)

2画面にして下の画面に棒グラフの出来高を追加

2画面にする場合は、bokeh.layoutsをインポートしておく必要があります。

from bokeh.layouts import column

以下が2画面、棒グラフの表示です。

解説

  • 前半部分は基本的に変わりません。(bokeh.layoutsのインポートは忘れずに
  • p1にfigureで2画面目のチャートを初期設定します。設定は基本的に1画面目と同じです。
    *今回は出来高(volume)データを表示させようとしましたが全て-1だったのbb_widthのカラムの値としています。

    • 2画面目もtoolsを指定できますが、今回は非表示としました。非表示にする場合はtoolbar_location=Noneと設定します。
    • toolbar_location=”below”とすると横向きになります。
      bokeh 横向きのツール
  • グリッドやXラベルの設定も同じです。今回は画面の都合上、Xラベルを斜めにしていません。
  • p1.x_range = p.x_rangeとても重要です。これを設定しておくと上下の2画面のX軸を連動させることができます。(これにハマりました。。。
  • p1.vbarで棒グラフを表示します。ローソク足と同じですが、むしろローソク足の方が棒グラフの応用という感じです。
  • ラベルの上書きを2画面目も行います。
  • 最後に、show(column(p,p1))columnで2画面をパックにして出力します。
# データフレームのマスクを設定
inc = df.close > df.open
dec = ~inc

# ローソク足の幅は固定
w = 0.5

TOOLS = "pan,wheel_zoom,box_zoom,box_select,crosshair,reset,save"

# 日時表示用のフォーマットを設定(日足と分足に分岐
xaxis_dt_format = '%d %b %Y'
if df.iloc[0]['date'].hour > 0:
    xaxis_dt_format = '%d %b %Y %H:%M:%S'

# チャートの設定
p = figure(
    x_axis_type="linear", # datetimeでは歯抜けになる。
    tools=TOOLS, 
    plot_width=1000, # チャートの幅
    title = "USD/JPY Candlestick 5 mins bar" # タイトルは任意に
)

p.xaxis.major_label_orientation = pi/4 # 日付を斜めに表示
p.grid.grid_line_alpha=0.3 # グリッドを薄く

# 以下のX軸を日付ではなくindexを設定するように変更
p.segment(df.index, df.high, df.index, df.low, color="black") # 高値と安値のラインを作成
p.vbar(df.index[inc], w, df.open[inc], df.close[inc], fill_color="#D5E1DD", line_color="black") # 陽線を作成
p.vbar(df.index[dec], w, df.open[dec], df.close[dec], fill_color="#F2583E", line_color="black") # 陰線を作成

# -------------------------------
# 出来高(bb_width   
p1 = figure(
    x_axis_type="linear",
#     tools=TOOLS, 
    toolbar_location=None,
    plot_width=1000,
    plot_height=150,
    title = ""
)

# p1.xaxis.major_label_orientation = pi/4 # 日付を斜めに表示
p1.grid.grid_line_alpha=0.3 # グリッドを薄く
p1.x_range = p.x_range
p1.vbar(df.index, w, df.bb_width)

# -------------------------------

# indexでラベルしたものを日付に上書き
p.xaxis.major_label_overrides = {
    i + 50: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
}
p1.xaxis.major_label_overrides = {
    i + 50: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
}

output_file("candlestick.html", title="candlestick.py example")

show(column(p,p1))

bokeh ローソク足チャートのサンプル 2画面

HTML版:bokeh_candlestick_example_two_windows

上のチャートに別のグラフを追加(ボリンジャーバンド

以下の3行を足すだけです。

p.line(df.index,df.bb_up, color = 'darkorange', legend = 'bb_up')
p.line(df.index,df.bb_mid, color = 'green', legend = 'bb_mid')
p.line(df.index,df.bb_low, color = 'darkorange', legend = 'bb_low')

*画像とサンプルHTMLは最後にまとめます。

下のチャートに別のグラフを追加(macd

追加するレンジが出来高と異なります。

そのため、まず以下のモジュールをインポートします。

from bokeh.models import LinearAxis, Range1d

追加するグラフのレンジを設定します。

# 追加するグラフの名称とレンジを設定
p1.extra_y_ranges = {"macd": Range1d(start=df.macd.min(), end=df.macd.max())}

# 設定したレンジを右側に追加 
p1.add_layout(LinearAxis(y_range_name="macd"), 'right')

追加するグラフを設定します。

ポイントは先程設定したレンジ名をy_range_name="macd"と指定していることです。その他は変わりありません。

p1.line(df.index, df.macd ,color = 'green', legend = 'macd', y_range_name="macd")
p1.line(df.index, df.signal ,color = 'yellow', legend = 'signal', y_range_name="macd")

*画像とサンプルHTMLは最後にまとめます。

応用のまとめ

from bokeh.plotting import figure, output_file, show
from bokeh.layouts import column
from bokeh.models import LinearAxis, Range1d

# データフレームのマスクを設定
inc = df.close > df.open
dec = ~inc

# ローソク足の幅は固定
w = 0.5

TOOLS = "pan,wheel_zoom,box_zoom,box_select,crosshair,reset,save"

# 日時表示用のフォーマットを設定(日足と分足に分岐
xaxis_dt_format = '%d %b %Y'
if df.iloc[0]['date'].hour > 0:
    xaxis_dt_format = '%d %b %Y %H:%M:%S'

# ------------------------------------------
# 1画面目(上の画面)

# 画面の初期設定
p = figure(
    x_axis_type="linear", # datetimeでは歯抜けになる。
    tools=TOOLS, 
    plot_width=1000, # チャートの幅
    title = "USD/JPY Candlestick 5 mins bar" # タイトルは任意に
)

p.xaxis.major_label_orientation = pi/4 # 日付を斜めに表示
p.grid.grid_line_alpha=0.3 # グリッドを薄く

# ローソク足の設定
p.segment(df.index, df.high, df.index, df.low, color="black") # 高値と安値のラインを作成
p.vbar(df.index[inc], w, df.open[inc], df.close[inc], fill_color="#D5E1DD", line_color="black") # 陽線を作成
p.vbar(df.index[dec], w, df.open[dec], df.close[dec], fill_color="#F2583E", line_color="black") # 陰線を作成

# 追加するチャートの設定
p.line(df.index,df.bb_up, color = 'darkorange', legend = 'bb_up')
p.line(df.index,df.bb_mid, color = 'green', legend = 'bb_mid')
p.line(df.index,df.bb_low, color = 'darkorange', legend = 'bb_low')

# ------------------------------------------
# 2画面目(下の画面)

# 画面の初期設定
p1 = figure(
    x_axis_type="linear",
#     tools=TOOLS, 
    toolbar_location=None,
    plot_width=1000,
    plot_height=150,
    title = ""
)

# 追加するグラフの名称とレンジを設定
p1.extra_y_ranges = {"macd": Range1d(start=df.macd.min(), end=df.macd.max())}

# 設定したレンジを右側に追加 
p1.add_layout(LinearAxis(y_range_name="macd"), 'right')

# p1.xaxis.major_label_orientation = pi/4 # 日付を斜めに表示
p1.grid.grid_line_alpha=0.3 # グリッドを薄く

# 上下の画面のX軸を連動
p1.x_range = p.x_range

# 棒グラフの設定(出来高
p1.vbar(df.index, w, df.volume)

# 追加するチャートの設定(macd
p1.line(df.index, df.macd ,color = 'green', legend = 'macd', y_range_name="macd")
p1.line(df.index, df.signal ,color = 'yellow', legend = 'signal', y_range_name="macd")

# ------------------------------------------
# indexでラベルしたものを日付に上書き
p.xaxis.major_label_overrides = {
    i + 50: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
}
p1.xaxis.major_label_overrides = {
    i + 50: date.strftime(xaxis_dt_format) for i, date in enumerate(df["date"])
}

# ラベルの位置を設定
p.legend.location = 'top_left'
p1.legend.location = 'top_left'

# ------------------------------------------
# 出力
output_file("candlestick.html", title="candlestick.py example")

show(column(p,p1))

bokeh ローソク足チャートのサンプル

HTML版:bokeh_candlestick_example

補足

チャートのライン間を塗りつぶし

以下のようにfigureに追加すれば塗りつぶすことができます。バンド系のチャートで利用することがありますね。

p.varea(x=df.index, y1=ラインの値1, y2=ラインの値2, color=色, alpha=濃さ)

以下は、一目均衡表(Ichimoku Cloud)と先行スパン1と先行スパン2の間を塗りつぶしの例です。

# 画面の初期設定
p = figure(
    x_axis_type="linear", # datetimeでは歯抜けになる。
    tools=TOOLS, 
    plot_width=1000, # チャートの幅
    title = "USD/JPY Candlestick 1 DAY bar" # タイトルは任意に
)

# ローソク足の設定
p.segment(df.index, df.High, df.index, df.Low, color="black") # 高値と安値のラインを作成
p.vbar(df.index[inc], w, df.Open[inc], df.Close[inc], fill_color="crimson", line_color="black") # 陽線を作成
p.vbar(df.index[dec], w, df.Open[dec], df.Close[dec], fill_color="royalblue", line_color="black") # 陰線を作成

# 追加するチャートの設定
p.line(df.index,df.tenkansen, color = 'green', legend = 'tenkansen')
p.line(df.index,df.kijunsen, color = 'darkred', legend = 'kijunsen')
p.line(df.index,df.chiku_span, color = 'blue', legend = 'chiku_span')
p.line(df.index,df.senkou_a, color = 'purple', legend = 'senkou_a')
p.line(df.index,df.senkou_b, color = 'lightgreen', legend = 'senkou_b')

p.varea(x=df.index, y1=df.senkou_a, y2=df.senkou_b, color = 'blue', alpha=0.1)

操作方法

基本的には触ってもらえればわかると思うのですが、1点だけ気付きにくいところがあるので説明します。

縦と横の目盛の幅(レンジ)もマウスのホイールで拡大・縮小ができます。

boken 拡大・縮小ボタンをクリックした後、目盛のラベルの上にマウスを持っていきホイールするだけです。

 

コメント

タイトルとURLをコピーしました