なにか投資, 投機的なものに興味を持つと必ず見るのがローソク足チャート。
今回はこのローソク足チャートを python で描いてみる。
Contents
背景
以前にローソク足チャートを別の方法で描こうとしたことがあったのだが、
そもそもまずローソク足チャートをネイティブに扱えるグラフ描画ライブラリが限定的で、
なんとか描けたとしても、横軸を時刻にすると取引が無い休日が飛んでしまったり、
元のOHLCデータ, 取引所, そして日本のタイムゾーンが異なるため、
4時間足が1日に7本になったり、日足が週に6本になったり、
これが結構なかなかどうして大変な作業であった。
今回、pandas と mplfinance を用いると驚くほど簡単に描けたので、
ローソク足データのダウンサンプリング(4時間足→日足など)方法と合わせて紹介する。
前提
前述の通り pandas と mplfinance を用いる。
matplotlib.finance や mpl_finance は DEPRECATED になっている。
conda install mplfinance
(miniforge/conda-forge) でも簡単に入れられる。
ダウンサンプリングについては、forexite 社提供の1分足データをベースにしたものに基づいて説明する。
(具体的なタイムゾーン切替など)
入力データの整備
入力データを pandas.DataFrame 格納する。
例えば以下のような感じ。
1 2 3 4 5 6 7 |
unixtime rate[0] rate[1] rate[2] rate[3] 0 1630447200 110.008797 110.008797 109.998802 109.998802 1 1630447260 109.998802 109.998802 109.998802 109.998802 2 1630447320 109.998802 109.998802 109.998802 109.998802 3 1630447380 109.998802 109.998802 109.998802 109.998802 4 1630447440 109.998802 109.998802 109.998802 109.998802 ... ... ... ... ... ... |
unixtime はエポック秒、rate[4] は順に open, high, low, close の値。
これを mplfinance で扱いやすい構造に整える。
index を DatetimeIndex にする
unixtime は unix秒なので、そのまま DatetimeIndex にできる。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[in]: import pandas as pd df['unixtime'] = pd.to_datetime(df['unixtime'], unit='s', utc=True) df.set_index("unixtime") [out]: rate[0] rate[1] rate[2] rate[3] unixtime 2021-08-31 22:00:00+00:00 110.008797 110.008797 109.998802 109.998802 2021-08-31 22:01:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:02:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:03:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:04:00+00:00 109.998802 109.998802 109.998802 109.998802 ... ... ... ... ... |
カラム名を合わせる
次に、OHLC(V) のカラム名は {'Open', 'High', 'Low', 'Close'(, 'Volume')}
にします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[in]: df.columns=['Open','High','Low','Close'] df [out]: Open High Low Close unixtime 2021-08-31 22:00:00+00:00 110.008797 110.008797 109.998802 109.998802 2021-08-31 22:01:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:02:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:03:00+00:00 109.998802 109.998802 109.998802 109.998802 2021-08-31 22:04:00+00:00 109.998802 109.998802 109.998802 109.998802 ... ... ... ... ... |
ローソク足チャートを描いてみる
mplfinance を使って以下で描ける。
1 2 3 |
import mplfinance as mpf mdf=df.tz_convert('Asia/Tokyo') mpf.plot(mdf[-60*9:], type='candle', figratio=(12,4), mav=(5, 20), style='yahoo') |
1行目:時刻を UTC ~ GMT として読み込んでいるので、日本時間表示に戻しています (mdf)。
df は UTC ~ GMT のままです(後述)。
2行目:mav は moving average (移動平均)の設定です。
上記の例では MA5, MA20 が合わせて表示されます。
style はローソク足とチャート全体のスタイルテーマを指定しています。
mpf.available_styles()
で一覧を取得できます。
ダウンサンプリングしてみる
1分足データからから15分足データを作ります。
1 2 3 4 5 6 |
d_ohlc = {'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last'} qdf=df.resample('15T', closed='left', label='left').agg(d_ohlc).tz_convert('Asia/Tokyo').dropna(how='any') qdf |
d_ohlc
で、ダウンサンプル時にどの値を採用するかを指定します。
'Volume' がある場合は 'sum' を指定するとよいでしょう。
'closed' は各データ区間の境界について、どちらの境界をその区間の値として含めるかを指定。
'label' はその区間のラベルとしていずれを用いるかの指定。
このようなチャートではいずれも 'left' で良いのではないかと思います。
日時は UTC~GMT になっているので、ダウンサンプリングを行った後は、tz_convert で JST に戻します。
dropna で欠損値を除外しています。
4時間足, 日足などへのダウンサンプリング
冒頭で触れたように forexite が提供している1分足のデータをダウンサンプリングしているわけですが、
1時間足までは良いのですが、4時間足, 日足、更には夏/冬時間などを考え始めると少し工夫と下処理が必要になります。
forexite 1分足の下処理
まず元データを見ると時刻が 00:01 - (翌日の) 00:00 までのような区切りになっています。
これは恐らく各1分足の終わりの時刻でラベル付されているのだと思います。
感覚としては Open の時刻でラベルしてあるほうが好みなので時刻を1分シフトして読み込みます。
次にこのデータにラベル付けされている時刻の時間帯についてですが、
冬/夏時間が切り替わる、3月における金曜終了時刻と翌週月曜開始時刻などの振る舞いから、
このデータは CET/CEST 系の時刻を載せていると思われます。
'データ' という観点では UTC の形で統一するほうがわかりやすいのではないかと思います。
python/pandas でこの処理を簡単に済ますには、以下のようにします。
1 2 |
df['unixtime'] = pd.to_datetime(df['unixtime'], unit='s') df=df.tz_localize('Europe/Brussels') |
さきほどと異なり、utc=True
オプションをつけていません。
これによりタイムゾーンの無い時刻として扱われます。
次に tz_localize
でタイムゾーン情報を追加します。
'Europe/Brussels' は CET/CEST を採用している都市の一例です。
これで tz_convert
でどのタイムゾーンにも正しく変換可能な 'utc' 的な時刻情報になりました。
# 冒頭のデータは読み込む前に外部で UTC化したものでした。
1時間足以上へのダウンサンプリング
FX取引は平日24時間続けて行われていますが、土日は取引がありません。
1週間の取引時間を日本時間で表現すると月曜7時から金曜31時(冬時間適用期)です。
夏時間適用期は月曜6時から金曜30時になります。
日本時刻で曜日をそのまま日足の基準にすると1週間が6日になってしまいます。
4時間足も1週間で30本より多くなってしまいます。
そこで夏時間を採用していて、日本と時差が -7/-6時間 となる GMT+2/GMT+3 時間帯の時刻を考えます。
この時間帯で1週間の取引時間を表現すると 月曜0時から金曜24時 となります。
これで4時間足, 日足も正しくダウンサンプリングできるようになります。
python/pandas で処理するなら、タイムゾーンを含む時間表現にした後、以下のようにします。
1 |
df=df.tz_convert('Europe/Athens') |
'Europe/Athens' は EET/EEST を採用している都市の一つです。
これをダウンサンプリング前に行うことで、resample
が基準がこの時間帯での時刻基準で行われます。
従ってデータを読み込んでプロットするまでの流れとしては、