回心誌

日々是回心

dukascopy-node で取得したデータをPython(Jupyter)で触る

前提

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で入手しなおすほうが楽だけども。