Price Channel を計算してみました。 せっかくなので、 python-highcharts を使ってローソク足と一緒に表示してみました。
Price Channel は Donchian Channel や High Low(HL) Bands とも呼ばれるそうです。
環境
- Ubuntu 16.04 LTS
- Python 3.5.2
- jupyter-1.0.0
- numpy-1.14.3
- pandas-0.22.0
- python-highcharts 0.5.2
準備
以前、ヒストリカルデータのリサンプリングをしたときと同じものを使いました。
Jupyter Notebook
Jupyter Notebook を使って 1 セルごとに実行しながら進めました。
モジュールを読み込む
npmpy と pandas と python-highcharts のモジュールを読み込みました。
import numpy as np
import pandas as pd
from highcharts import Highstock
ヒストリカルデータを読み込む
ヒストリカルデータを読み込みました。
次のような CSV の形式になっています。
$ head USDJPY_1\ Min_Bid_2000.01.01_2018.01.01.csv
Time (UTC),Open,High,Low,Close,Volume
2003.05.04 21:00:00,118.94,118.952,118.94,118.952,253
2003.05.04 21:01:00,118.961,118.967,118.958,118.967,154.6
2003.05.04 21:02:00,118.972,118.972,118.955,118.955,219.7
2003.05.04 21:03:00,118.953,118.961,118.949,118.949,309.9
2003.05.04 21:04:00,118.953,118.953,118.946,118.946,229.4
2003.05.04 21:05:00,118.952,118.954,118.944,118.944,112.2
2003.05.04 21:06:00,118.95,118.952,118.945,118.945,170.2
2003.05.04 21:07:00,118.947,118.956,118.947,118.947,124.5
2003.05.04 21:08:00,118.946,118.954,118.934,118.934,355
550 万件程度あるみたいです。
$ wc -l USDJPY_1\ Min_Bid_2000.01.01_2018.01.01.csv
5509561 USDJPY_1 Min_Bid_2000.01.01_2018.01.01.csv
pd.read_csv
で読み込んで DataFrame を生成しました。
filepath1 = 'USDJPY_1 Min_Bid_2000.01.01_2018.01.01.csv'
dtype1 = { 'time': str, 'open': float, 'high': float, 'low': float, 'close': float, 'volume': float }
names1 = ['time', 'open', 'high', 'low', 'close', 'volume']
%time df = pd.read_csv(filepath_or_buffer=filepath1, dtype=dtype1, header=0, index_col='time', names=names1, parse_dates=['time'])
df.head()
結果です。
open high low close volume
time
2003-05-04 21:00:00 118.940 118.952 118.940 118.952 253.0
2003-05-04 21:01:00 118.961 118.967 118.958 118.967 154.6
2003-05-04 21:02:00 118.972 118.972 118.955 118.955 219.7
2003-05-04 21:03:00 118.953 118.961 118.949 118.949 309.9
2003-05-04 21:04:00 118.953 118.953 118.946 118.946 229.4
EEST にする
時刻が UTC なので EEST にします。
data2 = { 'open': df['open'].values, 'high': df['high'].values, 'low': df['low'].values, 'close': df['close'].values, 'volume': df['volume'].values }
columns2 = ['open', 'high', 'low', 'close', 'volume']
index2 = df.index + pd.DateOffset(hours=3)
%time df2 = pd.DataFrame(data=data2, columns=columns2, index=index2)
df2.head()
結果です。
open high low close volume
time
2003-05-05 00:00:00 118.940 118.952 118.940 118.952 253.0
2003-05-05 00:01:00 118.961 118.967 118.958 118.967 154.6
2003-05-05 00:02:00 118.972 118.972 118.955 118.955 219.7
2003-05-05 00:03:00 118.953 118.961 118.949 118.949 309.9
2003-05-05 00:04:00 118.953 118.953 118.946 118.946 229.4
リサンプリング
1 分足から日足にリサンプリングしました。
%time df3 = df2.resample(rule='D').ohlc()
%time df4 = df2.resample(rule='D').sum()
data5 = { 'open': df3['open']['open'].values, 'high': df3['high']['high'].values, 'low': df3['low']['low'].values, 'close': df3['close']['close'].values, 'volume': df4['volume'].values }
columns5 = ['open', 'high', 'low', 'close', 'volume']
%time df5 = pd.DataFrame(data=data5, columns=columns5, index=df3.index).dropna()
df5.head()
結果です。
open high low close volume
time
2003-05-05 118.940 119.046 118.461 118.603 592866.9
2003-05-06 118.591 118.751 117.290 117.500 581707.0
2003-05-07 117.456 117.830 116.052 116.303 584496.2
2003-05-08 116.311 116.969 115.940 116.823 588236.7
2003-05-09 116.835 117.612 116.794 117.151 583132.9
高値と安値を計算する
ここから Price Channel の計算になります。
n 期間の高値と安値を計算します。
pandas の関数があるようで、最初、 pd.rolling_max
と pd.rolling_min
を使ったのですが、 pandas 0.22.0 では deprecated になっていました。
DataFrame.rolling(...).max()
と DataFrame.rolling(...).min()
を使うようです。
period = 20
%time high = df5['high'].rolling(window=period).max()
%time low = df5['low'].rolling(window=period).min()
%time pd.DataFrame(data={ 'high': high, 'low': low }).tail()
期間は 20 にしてみました。
結果です。
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 4.02 ms
CPU times: user 0 ns, sys: 0 ns, total: 0 ns
Wall time: 1.34 ms
high low
time
2017-12-28 113.75 111.993
2017-12-29 113.75 112.030
2017-12-30 113.75 112.030
2018-01-01 113.75 112.030
2018-01-02 113.75 112.030
日足にリサンプリングしたデータは 4,100 件程度ありましたが、わたしの環境では 1 ミリ秒から 5 ミリ秒程度で計算できました。
Highstock 向けの DataFrame を作る
python-highcharts に渡すデータの形式は 2 次元配列なので、それに合わせて DataFrame を作ります。
time6 = (df5.index.values // pd.Timedelta('1ms')).astype(np.int64)
data6 = { 'time': time6, 'open': df5['open'].values, 'high': df5['high'].values, 'low': df5['low'].values, 'close': df5['close'].values }
columns6 = ['time', 'open', 'high', 'low', 'close']
df6 = pd.DataFrame(data=data6, columns=columns6)
data7 = { 'time': time6, 'hlhigh': high.values }
columns7 = ['time', 'hlhigh']
df7 = pd.DataFrame(data=data7, columns=columns7)
data8 = { 'time': time6, 'hllow': low.values }
columns8 = ['time', 'hllow']
df8 = pd.DataFrame(data=data8, columns=columns8)
df6.merge(df7).merge(df8).tail()
df5
がローソク足のデータです。
df6
が Price Channel の高値のデータです。
df7
が Price Channel の安値のデータです。
DataFrame を index なしの行と列の形式にして、 df.values.tolist()
のようにすると 2 次元配列の形式で渡すことができるからこのようにしています。
index ありの DataFrame でも簡単に列の順番を考慮した 2 次元配列の形式にすることができるのかな。
df.values
が ndarray だから、 DataFrame にしなくても ndarray にできれば十分そうだけど、 pandas と NumPy の行き来がまだ不慣れです。
結果です。
time open high low close hlhigh hllow
4098 1514419200000 113.279 113.351 112.664 112.895 113.75 111.993
4099 1514505600000 112.894 112.969 112.472 112.678 113.75 112.030
4100 1514592000000 112.680 112.714 112.647 112.658 113.75 112.030
4101 1514764800000 112.658 112.658 112.658 112.658 113.75 112.030
4102 1514851200000 112.658 112.789 112.570 112.773 113.75 112.030
Highstock のローソク足と Price Channel を表示する
H = Highstock()
H.add_data_set(df6.values.tolist(), 'candlestick', '米ドル/円')
H.add_data_set(df7.values.tolist(), 'line', 'High')
H.add_data_set(df8.values.tolist(), 'line', 'Low')
options = {
'plotOptions': {
'line': {
'lineWidth': 1
}
},
'rangeSelector': {
'selected': 1
},
'title': {
'text': '米ドル/円 daily'
}
}
H.set_dict_options(options)
H
ローソク足のデータは H.add_data_set(df6.values.tolist(), 'candlestick', '米ドル/円')
のようにして渡しています。
Price Channel のデータは H.add_data_set(df7.values.tolist(), 'line', 'High')
と H.add_data_set(df8.values.tolist(), 'line', 'Low')
のように 2 つの折れ線グラフのデータとして渡しています。
オプションは Price Channel の折れ線グラフの線が太かったので細くしました。 それから、チャートを表示する範囲の初期値を 3m にしました。
結果は Jupyter Notebook Viewer から見ることができます。
Highstock の SMA (単純移動平均線)
Highstock のチャートのタイプに sma があったので、 python-highcharts でも使えるか試してみました。
が、 #OptionTypeError: Not An Accepted Option Type: sma
のようなエラーになってしまいました。
sma は使えないようでした。
pandas で計算すればいいや。
Gist のソース
Gist にアップしました。
Jupyter Notebook Viewer からチャートを見ることができます。
終わり
今はインディケーターは使わなくなったのですが、 Price Channel はタートルズも使っていたブレイクアウトの戦略を、自分でも検証してみたかったので計算してみました。
計算したデータで検証してみたいと思います。