この記事に書いてあること
結論から言えば、下図のようなチャートを描画するコードを書いています。
pythonで株式やfxのチャートを描画しようとすると、たいていmplfinanceに行きつきます。
しかしこの記事を書いている時点では情報がかなり少なく、意図したチャートを描くのは容易ではありません。
そこでこの記事では、複数のチャートを並列描画したり見た目をシンプルにしたりするコードについて書くことにしました。
コード
なにをおいてもまずはコードを書きます。
ポイントは以下の点です。
- グラフの文字サイズや色を指定すること (52行めから)
- 複数のチャートを描画するために枠組みを用意すること (61-69, 83-84, 126-127, 174-175行め)
- x軸のメモリを月曜ごとにしたりするなど (72-80, 120-123, 164-171行め)
# 元となる日足チャートは↓のような形式で用意しておきます。
# mplfinanceでは四本値の大文字小文字はこの通りにする必要があります。
# date Open High Low Close Volume
# 1990-01-04 38921.0 38950.0 38705.0 38712.0 4.720868e+08
# 1990-01-05 38717.0 38786.0 38090.0 38274.0 7.567594e+08
# 1990-01-08 38331.0 38564.0 38121.0 38294.0 5.200174e+08
# 1990-01-09 38281.0 38296.0 37729.0 37951.0 5.430759e+08
# 1990-01-10 37927.0 37927.0 37472.0 37696.0 5.538969e+08
# ..................
# 2021-07-09 27739.0 28000.0 27419.0 27940.0 1.425640e+09
# 2021-07-12 28412.0 28595.0 28405.0 28569.0 1.035770e+09
# 2021-07-13 28713.0 28852.0 28699.0 28718.0 9.575200e+08
# 2021-07-14 28517.0 28696.0 28482.0 28608.0 9.811800e+08
# 2021-07-15 28539.0 28571.0 28240.0 28279.0 9.711700e+08
# +-------------------+
# | ダウンサンプリング |
# +-------------------+
# サンプリングの仕方を指定する
d_ohlcv = {'Open': 'first', # 区間の最初の値
'High': 'max', # 区間の最大の値
'Low': 'min', # 区間の最小の値
'Close': 'last', # 区間の最後の値
'Volume': 'sum'} # 区間の和
# 日足から週足をつくる
df_w = df_d.resample('W-MON', closed='left', label='left').agg(d_ohlcv)
# W-MON: Wは週ごとの集約。MONは月曜起点
# closed: 開始日時と終了日時のどちらを期間に含むかを指定
# closed='left'なら開始日時 ≦ 期間 < 終了日時となり、'right'なら開始日時 < 期間 ≦ 終了日時
# label: ラベルを開始日時にするか終了日時にするかを指定
# label='left'とすると開始日時、label='right'とすると終了日時がラベル
# 日足から月足をつくる
df_m = df_d.resample('MS').agg(d_ohlcv)
# +----------+
# | チャート |
# +----------+
# 日足も週足も月足も30本描くことにします
day = 30
week = 30
month = 30
df_d = df_d.tail(day)
df_w = df_w.tail(week)
df_m = df_m.tail(month)
fig = mpf.figure(figsize=(10, 5))
cs = mpf.make_mpf_style(gridcolor='black',
gridstyle='dotted',
facecolor='white',
edgecolor='#202426',
figcolor='white',
rc={'xtick.labelsize': 10,
'ytick.labelsize': 10,
'axes.labelsize': 10})
left = 0.07
left2 = 0.33 + left
left3 = 0.66 + left
width = 0.33 - left
under = 0.20
top = 0.05
height = (1 - under - top*2) / 2
under2 = under + height + top
# === 日足 ===
# 共通になるx軸の設定 (今回は月曜ごとのメモリにしたい)
dates = df_d.index.values
list_xtick = []
for date in dates:
weekday = pd.to_datetime(date).weekday()
if weekday == 0:
list_xtick.append(date)
list_xlim = [df_d.index[0] - pd.tseries.offsets.Day(1),
df_d.index[-1] + pd.tseries.offsets.Day(1)]
# ロウソク足と出来高を描画する枠を確保する
ax_price = fig.add_axes([left, under2, width, height], style=cs)
ax_volume = fig.add_axes([left, under, width, height], style=cs)
# ロウソク足の設定
ax_price.set_title('Daily', fontsize=10)
ax_price.tick_params(labelbottom=False,
labelleft=True,
labelright=True,
labeltop=False)
ax_price.set_xlim(list_xlim)
ax_price.set_xticks(list_xtick)
ax_price.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_price.yaxis.get_major_formatter().set_powerlimits((0,1))
# 出来高の設定
ax_volume.set_xlim(list_xlim)
ax_volume.set_xticks(list_xtick)
ax_volume.set_xticklabels([pd.to_datetime(x).strftime('%Y/%m/%d') for x in list_xtick], rotation=90)
ax_volume.set_ylabel('Volume')
ax_volume.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_volume.yaxis.get_major_formatter().set_powerlimits((0,1))
# 描画する
add_plot = [mpf.make_addplot(df_d['Volume'],
type='bar',
color='black',
ax=ax_volume,
secondary_y=False,
width=1)]
mpf.plot(df_d.loc[:, ['Open', 'High', 'Low', 'Close']],
type='candle',
ax=ax_price,
addplot=add_plot,
show_nontrading=True,
xrotation=90)
# === 週足 ===
# 共通になるx軸の設定 (今回は月曜ごとのメモリにしたい)
dates = df_w.index.values
list_xtick = dates[::4]
list_xlim = [df_w.index[0] - pd.tseries.offsets.Week(1), df_w.index[-1] + pd.tseries.offsets.Week(1)]
# ロウソク足と出来高を描画する枠を確保する
ax_price = fig.add_axes([left2, under2, width, height], style=cs)
ax_volume = fig.add_axes([left2, under, width, height], style=cs)
# ロウソク足の設定
ax_price.tick_params(labelbottom=False,
labelleft=True,
labelright=True,
labeltop=False)
ax_price.set_title('Weekly', fontsize=10)
ax_price.set_xlim(list_xlim)
ax_price.set_xticks(list_xtick)
ax_price.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_price.yaxis.get_major_formatter().set_powerlimits((0,1))
# 出来高の設定
ax_volume.set_xlim(list_xlim)
ax_volume.set_xticks(list_xtick)
ax_volume.set_xticklabels([pd.to_datetime(x).strftime('%Y/%m/%d') for x in list_xtick], rotation=90)
ax_volume.set_ylabel('Volume')
ax_volume.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_volume.yaxis.get_major_formatter().set_powerlimits((0,1))
# 描画する
add_plot = [mpf.make_addplot(df_w['Volume'],
type='bar',
color='black',
ax=ax_volume,
secondary_y=False,
width=7)]
mpf.plot(df_w.loc[:, ['Open', 'High', 'Low', 'Close']],
type='candle',
ax=ax_price,
addplot=add_plot,
show_nontrading=True,
style=cs,
xrotation=90)
# === 月足 ===
# 共通になるx軸の設定 (今回は月曜ごとのメモリにしたい)
dates = df_m.index.values
list_xtick = []
for date in dates:
month = pd.to_datetime(date).month
if month in [4, 7, 10, 1]:
list_xtick.append(date)
list_xlim = [df_m.index[0] - pd.tseries.offsets.MonthBegin(1), df_m.index[-1] + pd.tseries.offsets.MonthBegin(1)]
# ロウソク足と出来高を描画する枠を確保する
ax_price = fig.add_axes([left3, under2, width, height], style=cs)
ax_volume = fig.add_axes([left3, under, width, height], style=cs)
# ロウソク足の設定
ax_price.tick_params(labelbottom=False,
labelleft=True,
labelright=True,
labeltop=False)
ax_price.set_title('Monthly', fontsize=10)
ax_price.set_xlim(list_xlim)
ax_price.set_xticks(list_xtick)
ax_price.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_price.yaxis.get_major_formatter().set_powerlimits((0,1))
# 出来高の設定
ax_volume.set_xlim(list_xlim)
ax_volume.set_xticks(list_xtick)
ax_volume.set_xticklabels([pd.to_datetime(x).strftime('%Y/%m/%d') for x in list_xtick], rotation=90)
ax_volume.set_ylabel('Volume')
ax_volume.yaxis.set_major_formatter(ScalarFormatter(useMathText=True))
ax_volume.yaxis.get_major_formatter().set_powerlimits((0,1))
# 描画する
add_plot = [mpf.make_addplot(df_m['Volume'],
type='bar',
color='black',
ax=ax_volume,
secondary_y=False,
width=31)]
mpf.plot(df_m.loc[:, ['Open', 'High', 'Low', 'Close']],
type='candle',
ax=ax_price,
addplot=add_plot,
show_nontrading=True,
style=cs,
xrotation=90)
fig.savefig('candlestick.png')
コメント