Binance永久先物の5秒足と1時間足で、移動平均とATRと戯れる
きっかけ
Binance永久先物の約定履歴と、いろんな時間間隔のタイムバーと戯れるで、色々な時間間隔のタイムバーを作って分析ができるようになったものの、どのタイムバーを選べばいいのかはまだよくわかっていません。
とりあえず、時間間隔が短い足と長い足で、移動平均線の振る舞いに違いがあるかを確認してみることにしました。
やること
5秒足と1時間足で7日移動平均と、1日移動平均の振る舞いに違いが見られるかを目視で確認する。
やったこと
以下のようなコードをJupyter Notebookで実行して確認しました。
(2019年10月から2022年10月までの5秒足のメモリ使用量がたったの1.5GBなのは助かります。約定履歴に比べてかなり扱いやすいです。)
コード
import pandas as pd
import matplotlib.pyplot as plt
import japanize_matplotlib
import exercise_util
df_1h = exercise_util.concat_timebar_files('BTCUSDT', 3600)
df_5sec = exercise_util.concat_timebar_files('BTCUSDT', 5)
df_1h['close_7dayma'] = df_1h['close'].rolling(7 * 24).mean()
df_1h['close_1dayma'] = df_1h['close'].rolling(24).mean()
df_5sec['close_7dayma'] = df_5sec['close'].rolling(7 * 24 * 60 * 60 // 5).mean()
df_5sec['close_1dayma'] = df_5sec['close'].rolling(24 * 60 * 60 // 5).mean()
print(df_1h.info())
print(df_5sec.info())
plt.plot(df_1h.loc[df_1h.index > '2022-10-24', 'close_7dayma'], label = 'df_1h.7dayMA', linewidth = 0, marker = 'x', markersize = 1)
plt.plot(df_1h.loc[df_1h.index > '2022-10-24', 'close'], label = 'df_1h.close', linewidth = 1, alpha = 0.5, color = 'blue')
plt.plot(df_5sec.loc[df_5sec.index > '2022-10-24', 'close_7dayma'], label = 'df_5sec.7dayMA', linewidth = 0, marker = '.', markersize = 1)
plt.plot(df_5sec.loc[df_5sec.index > '2022-10-24', 'close'], label = 'df_5sec.close', linewidth = 1, alpha = 0.5)
plt.xticks(rotation = 45)
plt.legend()
出力はこんな感じになりました。
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 27535 entries, 2019-09-08 17:00:00 to 2022-10-29 23:00:00
Freq: 3600S
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 open 27535 non-null float64
1 high 27535 non-null float64
2 low 27535 non-null float64
3 close 27535 non-null float64
4 buy_trade_count 27535 non-null int64
5 sell_trade_count 27535 non-null int64
6 quote_buy_volume 27535 non-null float64
7 quote_sell_volume 27535 non-null float64
8 close_7dayma 27368 non-null float64
9 close_1dayma 27512 non-null float64
dtypes: float64(8), int64(2)
memory usage: 2.3 MB
None
<class 'pandas.core.frame.DataFrame'>
DatetimeIndex: 18869760 entries, 2019-09-13 00:00:00 to 2022-10-29 23:59:55
Data columns (total 10 columns):
# Column Dtype
--- ------ -----
0 open float64
1 high float64
2 low float64
3 close float64
4 buy_trade_count int64
5 sell_trade_count int64
6 quote_buy_volume float64
7 quote_sell_volume float64
8 close_7dayma float64
9 close_1dayma float64
dtypes: float64(8), int64(2)
memory usage: 1.5 GB
7日移動平均のグラフ
1日移動平均のグラフ
なぜだか1時間足で作った移動平均のほうが、5秒足よりも先行しているようですが…あ、そうか。
タイムバーのインデックスは、そのタイムバーがオープンした瞬間なんでした。なので、1時間足のほうが5秒足よりもおおよそ1時間前にクローズ価格がプロットされてしまうんですね。なので、クローズ価格をshift(1)してからあれこれ計算する必要がありそうです。
気を取り直してプロットし直すと…。
7日移動平均のグラフ
1日移動平均のグラフ
タイムバーの時間間隔が違っても、移動平均はほぼ同じ値をとることがわかりました。
ATRはどうだろう
移動平均については、時間間隔の小さいタイムバーと時間間隔の大きいタイムバーはほぼ同じ値を取ることがわかりました。これなら、長い時間間隔のタイムバーで使ったロジックを短い時間間隔のタイムバーに移植できるかも?
ただ、タイムバーの間隔に大きな影響を受けるインジケーターもあります。例えばATRの計算方法は以下の3つの最大値を該当タイムバーのATRとし、n日 (一般的には14日) 分の平均値を取ってATRとします。
- 該当タイムバーのHigh – 該当タイムバーのLow
- 該当タイムバーのHigh – 直前タイムバーのClose
- 該当タイムバーのLow – 直前タイムバーのClose
この場合、5秒足のATRは1時間足のATRよりもずっと小さなものになってしまいますので、以下のように安直に移動平均と同じように処理をすると、全く違うインジケータの値になってしまいます。
df_1h['1dayatr'] = talib.ATR(df_1h['high'], df_1h['low'], df_1h['close'], timeperiod = 24)
df_5sec['1dayatr'] = talib.ATR(df_5sec['high'], df_5sec['low'], df_5sec['close'], timeperiod = 24 * 60 * 60 // 5)
タイムバーの間隔によって明らかに値の違うATRのグラフ
おわりに
ということで、同じロジックをいろいろな時間間隔のタイムバーで使いまわす場合は、執行ロジックがタイムバーの時間間隔に強く依存したインジケーターを使っていないかに注意する必要があることがわかりました。
Discussion