ボラティリティの拡縮の連続性


ボラティリティの拡縮の連続性

ボラティリティの拡大、または縮小には連続性があるかどうかを調べてみる。


環境


  • Ubuntu 18.04 LTS 64bit版

  • Firefox 65.0.1 (64 ビット)

  • Python 3.6.7

  • Jupyter Notebook 5.7.4


データのダウンロード

今回は2018年のUSDJPYのデータを使うことにする。HistData.comのデータが登録やデモ口座の開設も必要なしにcsvファイルでダウンロードできるので、これを使う。

①以下のアドレスをクリックする。

http://www.histdata.com/download-free-forex-historical-data/?/ascii/1-minute-bar-quotes/usdjpy/2018

②「HISTDATA_COM_ASCII_USDJPY_M12018.zip」をクリックする。

③「HISTDATA_COM_ASCII_USDJPY_M12018.zip を開く」で「ファイルを保存する」を選択する。

④「OK」ボタンをクリックする。

私の環境では「~/ダウンロード」フォルダーに保存される。

⑤端末で以下のコマンドを実行する。

cd ~/ダウンロード; \

unzip HISTDATA_COM_ASCII_USDJPY_M12018.zip


検証

ダウンロードしたデータは1分足だが、ここでは1時間足に変換して使う。

現在の足の高値-安値が前の足のそれより大きければ拡大、小さければ縮小とし、「拡大→拡大」、「拡大→縮小」、「縮小→拡大」、「縮小→縮小」の4つのパターンはそれぞれ何%を占めるかを見てみる。

import numpy as np

import pandas as pd
from collections import OrderedDict

# ダウンロードしたデータは1分足だが、ここでは1時間足に変換して使う。
df = pd.read_csv('~/ダウンロード/DAT_ASCII_USDJPY_M1_2018.csv', sep=';',
names=('open', 'high', 'low', 'close', 'volume'))
df.index = pd.to_datetime(df.index)
ohlcv_dict = OrderedDict()
ohlcv_dict['open'] = 'first'
ohlcv_dict['high'] = 'max'
ohlcv_dict['low'] = 'min'
ohlcv_dict['close'] = 'last'
ohlcv_dict['volume'] = 'sum'
df = df.resample('60T', label='left', closed='left').apply(ohlcv_dict)
df = df.dropna()
hi = df.high
lo = df.low
# 現在の足の高値-安値が前の足のそれより大きければ拡大、小さければ縮小とする。
expansion = (hi-lo) > (hi-lo).shift()
expansion = expansion.astype(int)
contraction = (hi-lo) < (hi-lo).shift()
contraction = contraction.astype(int)
scaling = expansion - contraction
scaling[scaling==0] = np.nan
scaling = scaling.dropna()
scaling = scaling.astype(int)
type1 = ((scaling==1)&(scaling.shift()==1)).sum() # 拡大→拡大
type2 = ((scaling==1)&(scaling.shift()==-1)).sum() # 拡大→縮小
type3 = ((scaling==-1)&(scaling.shift()==1)).sum() # 縮小→拡大
type4 = ((scaling==-1)&(scaling.shift()==-1)).sum() # 縮小→縮小
n_data = len(scaling)
print('拡大→拡大:' + str(np.round(type1/n_data*100.0, 1)) + '%')
print('拡大→縮小:' + str(np.round(type2/n_data*100.0, 1)) + '%')
print('縮小→拡大:' + str(np.round(type3/n_data*100.0, 1)) + '%')
print('縮小→縮小:' + str(np.round(type4/n_data*100.0, 1)) + '%')

拡大→拡大:16.8%

拡大→縮小:30.9%
縮小→拡大:30.9%
縮小→縮小:21.4%


結果

直感的には4つのパターンの起こりやすさは同等であり、それぞれ25%前後となるように思われる。だが、そのような結果にはならなかった。

最も多いのは「拡大→縮小」と「縮小→拡大」で、いずれも30.9%であり、次いで「縮小→縮小」の21.4%となり、「拡大→拡大」の16.8%が最も少ない。

現在の足でボラティリティが拡大した場合、次の足では約2/3が縮小、約1/3が拡大となり、逆に現在の足でボラティリティが縮小した場合、次の足では約3/5が拡大、約2/5が縮小となっている。

従って、ボラティリティの拡大、または縮小には連続性があるようには見えない。現在の足でボラティリティが拡大したなら次の足では縮小、現在の足でボラティリティが縮小したなら次の足では拡大と予測したほうが的中率は高くなるだろう。


再検証

本当か? ちょっと疑わしいのでランダムウォークのデータを作成し、同じ検証を行ってみる。

import numpy as np

import pandas as pd
from collections import OrderedDict

# 10秒間隔のランダムウォークデータで1分足を作成し、それを1時間足に変換して使う。
start = '2018.01.01 00:00:00'
end = '2018.12.31 23:59:00'
index = pd.date_range(start, end, freq='10S')
index = index[index.dayofweek<5]
n = len(index)
np.random.seed(0)
rnd = np.random.normal(0.0, 0.00003, n)
randomwalk = rnd.cumsum() + np.log(100)
randomwalk = np.exp(randomwalk)
randomwalk = pd.Series(randomwalk, index=index)
randomwalk1 = randomwalk.resample('T').ohlc()
volume = pd.DataFrame([6]*len(randomwalk1), index=randomwalk1.index,
columns=['volume'])
randomwalk1 = pd.concat([randomwalk1, volume], axis=1)
ohlcv_dict = OrderedDict()
ohlcv_dict['open'] = 'first'
ohlcv_dict['high'] = 'max'
ohlcv_dict['low'] = 'min'
ohlcv_dict['close'] = 'last'
ohlcv_dict['volume'] = 'sum'
df = randomwalk1.resample(
'60T', label='left', closed='left').apply(ohlcv_dict)
df = df[df.index.dayofweek<5]
df = df.dropna()
hi = df.high
lo = df.low
# 現在の足の高値-安値が前の足のそれより大きければ拡大、小さければ縮小とする。
expansion = (hi-lo) > (hi-lo).shift()
expansion = expansion.astype(int)
contraction = (hi-lo) < (hi-lo).shift()
contraction = contraction.astype(int)
scaling = expansion - contraction
scaling[scaling==0] = np.nan
scaling = scaling.dropna()
scaling = scaling.astype(int)
type1 = ((scaling==1)&(scaling.shift()==1)).sum() # 拡大→拡大
type2 = ((scaling==1)&(scaling.shift()==-1)).sum() # 拡大→縮小
type3 = ((scaling==-1)&(scaling.shift()==1)).sum() # 縮小→拡大
type4 = ((scaling==-1)&(scaling.shift()==-1)).sum() # 縮小→縮小
n_data = len(scaling)
print('拡大→拡大:' + str(np.round(type1/n_data*100.0, 1)) + '%')
print('拡大→縮小:' + str(np.round(type2/n_data*100.0, 1)) + '%')
print('縮小→拡大:' + str(np.round(type3/n_data*100.0, 1)) + '%')
print('縮小→縮小:' + str(np.round(type4/n_data*100.0, 1)) + '%')

拡大→拡大:16.5%

拡大→縮小:33.5%
縮小→拡大:33.5%
縮小→縮小:16.6%


再結果

やはり直感は当てにならないもので、4つのパターンの起こりやすさは同等ではない。足の長さをいろいろ変えて試したところ、どうやら

拡大→拡大:16.7%

拡大→縮小:33.3%
縮小→拡大:33.3%
縮小→縮小:16.7%

に落ち着くようだ。これを理論値と考えていいだろう。どうしてそうなるのかは分からないが(汗)。

最初の検証結果と比較すると、「拡大→拡大」はほぼ理論値通りで、「拡大→縮小」と「縮小→拡大」は理論値よりやや少なく、その分が「縮小→縮小」の増加に繋がっている。

「現在の足でボラティリティが拡大したなら次の足では縮小、現在の足でボラティリティが縮小したなら次の足では拡大と予測したほうが的中率は高くなる」という現象はランダムウォークのデータでも起きている。したがってUSDJPYのデータに偏りがあるという訳ではない。だが「縮小→縮小」については理論値より大きく、偏りがあると言える。

さて、この偏りを利用したトレード戦略は可能であるだろうか。それは今後の研究課題としておこう。