Python で 1 分足のヒストリカルデータから日足のデータを作りました

売買ルールを検証するのに Python を使ってみようと思いました。 かなりメカニカル、機械的にトレードをするようになったので、検証もメカニカルにプログラムを使ってできないかと思い始めています。 でも、 MT4 の EA のような、システムトレードをしたいわけではないです。

今回は、データを用意するところを書いてみます。

環境

  • Ubuntu 16.04 LTS
  • Python 3.5.2
  • jupyter-1.0.0
  • pandas-0.22.0
  • numpy-1.14.3
  • matplotlib-2.2.2

次の記事にあるように Jupyter Notebook と pandas と matplotlib をインストールしておきました。

データ

デューカスコピー・ジャパンのヒストリカルデータ取得のページを参考にデータをダウンロードしました。

ダウンロードするのにデモ口座を開設しました。 30 日で期限が切れるようです。 依頼すれば期限を延ばすこともできるみたいです。 プライバシーの問題があるので、放置していても期限が切れるのはありがたいです。

JForex を使ってダウンロードしたのですが、 AppData の下に一時的なファイルを作るようです。 1 通貨ペア当たり数百 MB 程度あったので、複数通貨ペアだと数 GB になります。 JForex をアンインストールしても残っていたので、気になる場合はちゃんと AppData の下も削除した方がよさそうでした。

データの形式は 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

USD/JPY のデータを 2001 年からダウンロードしたのですが、 2003 からしかなかったみたいです。

プログラム

ここからは Jupyter Notebook を使って Python のプログラムを実行していきます。 この記事の 1 つのコードブロックを、 Jupyter Notebook の 1 つのセルに入力しながら進めました。

モジュールを読み込む

matplotlib のマジックコマンドを記述しました。 それから、必要なモジュールを読み込みました。 matplotlib と pandas を使っています。

%matplotlib inline
import matplotlib.pyplot as plt
import pandas as pd

データを読み込む

データを読み込みました。 pandas の read_csv を使うと CSV ファイルから読み込めるようです

dtype1 = { 'time': str, 'open': float, 'high': float, 'low': float, 'close': float, 'volume': float }
names1 = ['time', 'open', 'high', 'low', 'close', 'volume']
df = pd.read_csv(filepath_or_buffer='USDJPY_1 Min_Bid_2000.01.01_2018.01.01.csv', 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(UTC+3) に直しました。 こうすると、週の始まりのデータが 2003-05-04 21:00:00 (日)から 2003-05-05 00:00:00 (月)になって、日足のローソク足が 5 本になります。 EEST が為替の業界の標準のようです(たぶん)。 ここでは UTC に対して +3 時間の計算をしています。

data1 = { 'open': df['open'].values, 'high': df['high'].values, 'low': df['low'].values, 'close': df['close'].values, 'volume': df['volume'].values }
columns1 = ['open', 'high', 'low', 'close', 'volume']
index1 = df.index + pd.DateOffset(hours=3)
df2 = pd.DataFrame(data=data1, columns=columns1, index=index1)
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

ちゃんと月曜日の 0 時から始まっているようです。

日足にリサンプリングする

データは 1 分足のものなので、日足にリサンプリングします。 resample'D' を渡すと日ごとにサンプリングしてくれるようです。 ohlc で、始値 (O) 、高値 (H) 、安値 (L) 、終値 (C) を計算してくれるようです。 ohlc は、 pandas の Series ごとに OHLC を計算してくれるようなので、始値を参照する場合は、 df['open']['open'] のように記述する必要があるようです。

まだ必要かわからないですけど、入力したデータに出来高もあったので、出来高は sum で日ごとの合計を計算しました。

リサンプリングしたら土日も含まれてしまっていたので、 dropna で取り除きました。

df3 = df2.resample(rule='D').ohlc()
df4 = df2.resample(rule='D').sum()
data2 = { 'open': df3['open']['open'].values, 'high': df3['high']['high'].values, 'low': df3['low']['low'].values, 'close': df3['close']['close'].values, 'volume': df4['volume'].values }
columns2 = ['open', 'high', 'low', 'close', 'volume']
df5 = pd.DataFrame(data=data2, columns=columns2, 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

日ごとにサンプリングできたみたいです。

グラフを表示する

終値を折れ線グラフに表示してみました。

df5.plot(y='close')

結果は .ipynb ファイルを Gist にアップしました。

CSV ファイルを作る

それから、日足のデータを CSV ファイルにしました。

df5.to_csv(path_or_buf='USDJPY_daily.csv')

結果です。

time,open,high,low,close,volume
2003-05-05,118.94,119.046,118.461,118.603,592866.9000000006
2003-05-06,118.59100000000001,118.751,117.29,117.5,581707.0000000001
2003-05-07,117.456,117.83,116.052,116.303,584496.2000000001
2003-05-08,116.311,116.969,115.94,116.823,588236.6999999998
2003-05-09,116.835,117.61200000000001,116.794,117.15100000000001,583132.8999999994
2003-05-12,117.286,117.286,116.304,117.025,586660.3000000002
2003-05-13,117.053,117.52799999999999,116.338,116.561,584984.3999999999
2003-05-14,116.554,116.837,115.557,116.16,586464.9000000006
2003-05-15,116.17299999999999,116.525,115.28200000000001,116.515,585585.1000000006

うーん、小数点以下に誤差が出てしまっています。 検証に影響あるかな。 どうかな。

取引業者によって提示している価格に差はあるでしょうし、特定の業者に限定して取引をした場合だけ成績が良くても仕方ないので、今はこのまま進めようと思います。 これくらいの誤差程度で大きな影響を受けるようじゃ、堅牢な売買ルールとは言えないんじゃないか、とも思いますし。

終わり

pandas は便利で、 resample で 1 時間足でも 2 時間足でも 15 分足でも作れるみたいです。 そのときに引数の rule に渡す値は Offset Aliases にあるもののようです。 15 分足だったら 15T15min のようにできそうです。

23 May 2018 追記

pandas は簡単に四捨五入できました。

df5.round({ 'open': 3, 'high': 3, 'low': 3, 'close': 3, 'volume': 1 }).to_csv(path_or_buf='USDJPY_daily.csv')

結果です。

time,open,high,low,close,volume
2003-05-05,118.94,119.046,118.461,118.603,592866.9
2003-05-06,118.591,118.751,117.29,117.5,581707.0
2003-05-07,117.456,117.83,116.052,116.303,584496.2
2003-05-08,116.311,116.969,115.94,116.823,588236.7
2003-05-09,116.835,117.612,116.794,117.151,583132.9
2003-05-12,117.286,117.286,116.304,117.025,586660.3
2003-05-13,117.053,117.528,116.338,116.561,584984.4
2003-05-14,116.554,116.837,115.557,116.16,586464.9
2003-05-15,116.173,116.525,115.282,116.515,585585.1

23 May 2018 追記

次の記事を書きました。