前提
WSL2
Python 3.10.12
Jupyter Notebook
やりたいこと
dukascopy-nodeで取得したデータをPythonで触ってみる。
どういう性質があるかを確認する。
今回は対象を以下のコードで取得したOHLCデータとする。
npx dukascopy-node -i usdjpy -from 2023-01-24 -to 2023-01-25 -t s1 -f csv -v true -fl false
さっそくやってみる
とりあえず落としたデータの中身を見てみる
import pandas as pd filepath = "~/download/usdjpy-s1-bid-2023-01-24-2023-01-25.csv" df = pd.read_csv(filepath) df
timestamp open high low close volume 0 1674518401000 130.593 130.593 130.577 130.577 14.15 1 1674518402000 130.578 130.579 130.577 130.578 8.40 2 1674518403000 130.579 130.579 130.570 130.570 7.05 3 1674518404000 130.576 130.579 130.575 130.575 7.17 4 1674518405000 130.573 130.578 130.573 130.578 7.19 ... ... ... ... ... ... ... 51790 1674604791000 130.203 130.207 130.203 130.207 6.00 51791 1674604792000 130.206 130.206 130.206 130.206 4.50 51792 1674604793000 130.207 130.208 130.207 130.208 4.80 51793 1674604796000 130.210 130.210 130.210 130.210 3.60 51794 1674604799000 130.209 130.212 130.209 130.210 14.85 51795 rows × 6 columns
タイムスタンプ列はミリ秒単位のUNIX単位になっている。
それ以外の列はOHLCと出来高(Volume)だが、列名はすべて小文字(lowercase)。
微妙に面倒なのか、Backtestingで扱おうとすると列名は最初大文字それ以外小文字(title case)にする必要がある。
Backtesting.py - Backtest trading strategies in Python
1秒間隔になっていない行もある。
60 * 60 * 24が86400、つまり24時間で1秒間隔でデータを取ると86399行になるはず。
51795行しかないということは34604行分のデータが失われているということになる。
欠損値の確認。nullは存在しない。
df.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 51795 entries, 0 to 51794 Data columns (total 6 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 timestamp 51795 non-null int64 1 open 51795 non-null float64 2 high 51795 non-null float64 3 low 51795 non-null float64 4 close 51795 non-null float64 5 volume 51795 non-null float64 dtypes: float64(5), int64(1) memory usage: 2.4 MB
時刻をUNIX時間からDatetimeに変換
# timestamp列を日時に変換 df['date'] = pd.to_datetime(df['timestamp'], unit='ms') df = df.set_index('date') del df['timestamp'] df
open high low close volume date 2023-01-24 00:00:01 130.593 130.593 130.577 130.577 14.15 2023-01-24 00:00:02 130.578 130.579 130.577 130.578 8.40 2023-01-24 00:00:03 130.579 130.579 130.570 130.570 7.05 2023-01-24 00:00:04 130.576 130.579 130.575 130.575 7.17 2023-01-24 00:00:05 130.573 130.578 130.573 130.578 7.19 ... ... ... ... ... ... 2023-01-24 23:59:51 130.203 130.207 130.203 130.207 6.00 2023-01-24 23:59:52 130.206 130.206 130.206 130.206 4.50 2023-01-24 23:59:53 130.207 130.208 130.207 130.208 4.80 2023-01-24 23:59:56 130.210 130.210 130.210 130.210 3.60 2023-01-24 23:59:59 130.209 130.212 130.209 130.210 14.85 51795 rows × 5 columns
列名をlowercaseからtitlecaseに変更
# 列名をTitle Caseに変換 df.columns = [col.title() for col in df.columns] df
Open High Low Close Volume date 2023-01-24 00:00:01 130.593 130.593 130.577 130.577 14.15 2023-01-24 00:00:02 130.578 130.579 130.577 130.578 8.40 2023-01-24 00:00:03 130.579 130.579 130.570 130.570 7.05 2023-01-24 00:00:04 130.576 130.579 130.575 130.575 7.17 2023-01-24 00:00:05 130.573 130.578 130.573 130.578 7.19 ... ... ... ... ... ... 2023-01-24 23:59:51 130.203 130.207 130.203 130.207 6.00 2023-01-24 23:59:52 130.206 130.206 130.206 130.206 4.50 2023-01-24 23:59:53 130.207 130.208 130.207 130.208 4.80 2023-01-24 23:59:56 130.210 130.210 130.210 130.210 3.60 2023-01-24 23:59:59 130.209 130.212 130.209 130.210 14.85 51795 rows × 5 columns
前の行との時間差を求めて列として追加する
df['time_difference'] = df.index.to_series().diff().dt.total_seconds() df
分単位にしたい場合は/60
をつけて割り算すればいい。
Open High Low Close Volume time_difference date 2023-01-24 00:00:01 130.593 130.593 130.577 130.577 14.15 NaN 2023-01-24 00:00:02 130.578 130.579 130.577 130.578 8.40 1.0 2023-01-24 00:00:03 130.579 130.579 130.570 130.570 7.05 1.0 2023-01-24 00:00:04 130.576 130.579 130.575 130.575 7.17 1.0 2023-01-24 00:00:05 130.573 130.578 130.573 130.578 7.19 1.0 ... ... ... ... ... ... ... 2023-01-24 23:59:51 130.203 130.207 130.203 130.207 6.00 1.0 2023-01-24 23:59:52 130.206 130.206 130.206 130.206 4.50 1.0 2023-01-24 23:59:53 130.207 130.208 130.207 130.208 4.80 1.0 2023-01-24 23:59:56 130.210 130.210 130.210 130.210 3.60 3.0 2023-01-24 23:59:59 130.209 130.212 130.209 130.210 14.85 3.0 51795 rows × 6 columns
1秒間隔になっていないデータにはどういう意味があるだろうか。
- 単純に取引がされていない。
- 欠損しており、あるはずのデータが抜けている。
とりあえず、欠損してるデータってどれくらいの間隔なのか見てみる。
大きいのだと222秒。
df.sort_values(by='time_difference', ascending=False).head()
Open High Low Close Volume time_difference date 2023-01-24 22:44:46 130.174 130.174 130.174 130.174 1.1 222.0 2023-01-24 22:03:52 130.178 130.178 130.176 130.176 2.7 165.0 2023-01-24 22:26:49 130.160 130.160 130.160 130.160 1.6 119.0 2023-01-24 22:47:10 130.181 130.181 130.181 130.181 1.2 90.0 2023-01-24 22:05:04 130.175 130.175 130.175 130.175 1.2 72.0
出来高が小さい気がする。
試しに出来高の平均を、
- データ全体
- 前のデータとの間隔が大きいもの
でそれぞれ求めて比較してみる
print(df['Volume'].mean()) print(df[df['time_difference'] != 1]['Volume'].mean())
8.055379669852302 5.8763571265331
うーん、まあ取引が少ないからデータが存在しないって感じはするなあ。
1秒足のデータを5分足に変換する
# 5分足に変換 df_5min = df.resample('5min').agg({ 'Open': 'first', 'High': 'max', 'Low': 'min', 'Close': 'last', 'Volume': 'sum' }) df_5min
Open High Low Close Volume date 2023-01-24 00:00:00 130.593 130.670 130.570 130.657 736.36 2023-01-24 00:05:00 130.658 130.728 130.635 130.646 752.12 2023-01-24 00:10:00 130.645 130.671 130.565 130.580 751.92 2023-01-24 00:15:00 130.579 130.580 130.416 130.471 910.78 2023-01-24 00:20:00 130.472 130.510 130.468 130.499 663.19
まあ、わざわざこうするよりか普通にdukascopy-nodeで入手しなおすほうが楽だけども。