売買ルールを検証するのに 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 分足だったら 15T
か 15min
のようにできそうです。
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 追記
次の記事を書きました。