こんにちは。システムトレーダーの卵ことKenKenです。前回の記事では、日経225先物の2007年から直近のデータについて分析しました。寄り付きと引けの価格差に着目し、日中、日中~夜間、夜間、夜間~日中の4パターンについてみてきました。結果としては、夜間取引の寄付と引けで正のリターンが得られる可能性が見られました。また、2013年を境にリターンが反転している様子も見られました。
(使用データ、分析手順等については前回の記事をご参照ください。)
そこで、今回は分析対象期間を2013年以降として、より明確な特徴が得られるか分析をしてみます。分析手順については、前回とほぼ同じになります。今回も「Python3ではじめるシステムトレード ──環境構築と売買戦略」を参考にしております。
分析
まずは、2013年以降について以下の4パターンごとに1日ごとの価格差の累積和をグラフにする。
- 日中取引の寄りから引けまでの価格の動き(daytime)
- 日中立ち合いの引けから夜間立ち合いの寄りまでの価格の動き(d_to_n)
- 夜間立ち合いの寄りから引けまでの価格の動き(night)
- 夜間立ち合いの引けから日中立ち合いの寄りまでの価格の動き(n_to_d)
import numpy as np import pandas as pd import matplotlib.pyplot as plt # 日経225先物データを読み込む N225_daytime = pd.read_excel('./data/N225f_2020.xlsx', sheet_name='日中日足', index_col='日付') N225_night = pd.read_excel('./data/N225f_2020.xlsx', sheet_name='ナイト場足', index_col='日付') # 結合し、2013年以降にする df = pd.merge(N225_daytime, N225_night, on='日付', suffixes=['_D', '_N'])['2013/1/1':] # D:daytime, N:night # 各パターンの価格差を求める daytime = df['終値_D'] - df['始値_D'] d_to_n = df['始値_N'] - df['終値_D'] night = df['終値_N'] - df['始値_N'] n_to_d = df['始値_D'] - df['終値_N'].shift(1) # 価格差の累積和をグラフにする plt.figure(figsize=(8, 6)) daytime.cumsum().plot(label='daytime') d_to_n.cumsum().plot(label='d_to_n') night.cumsum().plot(label='night') n_to_d.cumsum().plot(label='n_to_d') plt.legend(loc='upper left')

グラフを見ると、赤線(日中~夜間)はリターンを積み上げており、橙色はその逆の動きをしている。推移が綺麗な真逆になっており、どこかでミスしているのではないかと疑いたくなるが、確認したところミスはないと思っている。夜間の引け~日中の寄りでプラスとなったリターンは、日中の寄り付け~引けを通してマイナスになり、結果として日中のリターンでは織り込まれてゼロとなっているのではないか。これは、前回も触れたが、情報の伝達が関係しているのかもしれない。
次にヒストグラムと記述統計を算出し、特徴を見てみる。
# ヒストグラムを書く plt.figure(figsize=(12, 4)) ax1 = plt.subplot(1, 2, 1) daytime.hist(label='daytime', histtype='step', linewidth=3, ax=ax1) d_to_n.hist(label='d_to_n', color='lightgreen', rwidth=0.7, ax=ax1) plt.legend() ax2 = plt.subplot(1, 2, 2) night.hist(label='night', histtype='step', linewidth=3, ax=ax2) n_to_d.hist(label='n_to_d', color='lightgreen', rwidth=0.7, ax=ax2) plt.legend() # 記述統計を算出 stats_desc = pd.concat([daytime.describe(), d_to_n.describe(), night.describe(), n_to_d.describe()],axis=1) stats_desc.columns = ['daytime', 'd_to_n', 'night', 'n_to_d'] pd.options.display.precision = 4 # dfの桁数を調整 stats_desc


上記のグラフでも触れたが、夜間、日中~夜間では平均はプラス、夜間~日中ではマイナスとなった。日中はゼロに近いとなっている。ヒストグラムを見ると、日中ではマイナスにすそ野が伸びているのが目立つ(歪度はマイナスになりそう)。他のパターンのヒストグラムは、概ね左右対称となった。n_to_dに関しては若干プラスの要素が多いようである。また、ボラティリティ(標準偏差)についても、日中~夜間、夜間~日中では始値と終値に乖離が生じることがあることから高い値となっている。
次に、ADF検定(ランダムウォークの検証)、t検定(平均値の状態)、JB検定(残差の正規性)を行う。結果は以下の通り。(左が有意水準10%、右が有意水準5%)
alpha = 0.1 patterns = {'daytime': daytime, 'd_to_n' : d_to_n, 'night' : night, 'n_to_d' : n_to_d} results = [] for key in patterns.keys(): target = patterns[key].dropna() # ADF検定 adf_nc = sm.tsa.adfuller(target, regression='nc')[1] #p値:ドリフト項無し adf_c = sm.tsa.adfuller(target, regression='c')[1] #p値:ドリフト項付き adf_ct = sm.tsa.adfuller(target, regression='ct')[1] #p値:ドリフト項+時間項付き # t検定 t_value = target.mean() * np.sqrt(target.count()) / target.std() t0 = t.ppf(1-alpha, target.count()-1) if t_value > t0: t_result = 'μ>0' elif t_value < -t0: t_result = 'μ<0' else: t_result = 'μ=0' # JB検定 JB = sms.jarque_bera(target) # JB, p値, 歪度, 尖度 # 結果を保存 results.append([adf_nc, adf_c, adf_ct, t_result, JB[1], JB[2], JB[3]]) # dfにまとめる df_result = pd.DataFrame(results, index=patterns.keys()) df_result.columns = ['ADF nc', 'ADF c', 'ADF ct', 't', 'JB', '歪度', '尖度'] df_result.T


ADF検定、JB検定は前回と同様となった。つまり、非定常過程ではなく、残差は正規性を持たない可能性が高い。一方、t検定については前回と異なる。前回は、有意水準10%においてどのパターンの平均\(\mu\)はゼロであったが、今回は有意にプラスとなった。しかし、5%水準では有意性は見られなかった。
ここまでの結果から、取引戦略としては、night(夜間寄り付け~夜間引け)かn_to_d(夜間引け~翌日寄り付け)の2つが候補に挙がる。ここで歪度についてみると、n_to_dはnightより分布がマイナスに寄っていることがわかる。つまり、リターンがマイナスをとりやすい。また、前回の記事では、全期間における分析で唯一、nightにだけプラスの優位性が見られた。したがって、取引戦略としては、nightを採用したほうが安定的にリターンを得られる可能性がある。平均はn_to_dの方が高いがその分ボラティリティも高い(リスクが高い)。
まとめ
前回と今回の2つの記事にわたり日経225先物の寄付~引けの特徴を見てきました。結果として、night(夜間取引の寄付~引け)で安定してリターンが得られる可能性が見られました。したがって、今後はnightをベースとした取引戦略を考えてみたいと思います。次回は、戦略に基づくシミュレーションになるのかな。
以上