イベントとボラティリティ

イベントの発生によってボラティリティがどのように変化するかを調べてみる。イベントにも様々な種類がある。ここでは定期的に発表される経済指標発表イベントを考えることにする。

だが、そのためには予めすべての経済指標発表のスケジュールを調べ、入力しておく必要がある。しかし、これは大変な作業だ。そこで逆に定期的にボラティリティの高くなる特定の時間を見つけ、そこでイベントが発生したと考えることとする。

先ず第1月曜日0時0分から第5金曜日23時55分まで、5分ごとのボラティリティを調べた。そして検証したすべての年においてボラティリティが平均の2倍以上となっている時間を抜き出した。この時間にイベントが発生したと考えるわけである。

ボラティリティが拡大する時間

足の種類は5分足である。ボラティリティを計る指標としてTrue Rangeを使っている。各年の平均を取って、それで除している。

グラフが細かすぎてよく分からない。だが、平均を大きく超える時間があるということは分かる。

縦の点線は週の切り替わるところとなっている。よく見ると、ここでボラティリティが高くなる傾向がある。だが、これはイベントではない。月曜早朝の窓開けである。

横の点線はボラティリティの平均である。よく見ると、週に5回、規則正しくボラティリティが平均を下回る時間帯がある。グラフでは分からないが、これは日付の変わる直前である。この時間帯ではイベントがないからだろう。

第5週は月によっては存在しない。データ数が他の週より少なくなるので、分散も大きい。最後のRANDOMを見ると分かる。

ボラティリティ拡大の時間リスト

グラフでは分からないので各通貨ペアごとにボラティリティが拡大する時間リストを作った。それぞれの通貨ペアで2012年初めから2016年終わりまでの5年間すべてでボラティリティが平均の2倍となっている時間である。

数値は(週、曜日, 時, 分)の順に並べている。曜日は1-5で月-金となっている。

(1, 5, 15, 30)、つまり、第1金曜日の15時30分はNYクロージングを0時0分とした場合の米雇用統計発表の時間である。すべての通貨ペアでこの時間のボラティリティは拡大している。その影響か、発表の1時間前から30分後までの1時間半はボラティリティが高くなる傾向がある。

当然ではあるが、RANDOMではボラティリティが拡大する特定の時間は存在しない。

AUDUSD
(1, 1, 0, 0)
(1, 2, 5, 30)
(1, 2, 6, 30)
(1, 2, 6, 35)
(1, 3, 3, 30)
(1, 4, 3, 30)
(1, 5, 14, 30)
(1, 5, 14, 35)
(1, 5, 14, 40)
(1, 5, 15, 30)
(1, 5, 15, 35)
(1, 5, 15, 45)
(1, 5, 16, 0)
(2, 1, 0, 0)
(2, 4, 3, 30)
(3, 2, 3, 30)
(4, 1, 0, 0)
(4, 3, 2, 30)
EURUSD
(1, 2, 16, 0)
(1, 3, 16, 0)
(1, 4, 14, 40)
(1, 4, 16, 0)
(1, 5, 14, 30)
(1, 5, 14, 35)
(1, 5, 14, 40)
(1, 5, 14, 45)
(1, 5, 15, 25)
(1, 5, 15, 30)
(1, 5, 15, 35)
(1, 5, 15, 40)
(1, 5, 15, 45)
(1, 5, 16, 0)
(2, 4, 14, 30)
(2, 4, 15, 30)
(2, 5, 15, 30)
(2, 5, 15, 40)
(2, 5, 16, 0)
(2, 5, 17, 0)
(3, 1, 0, 0)
(3, 4, 14, 30)
(3, 4, 16, 0)
(4, 1, 0, 0)
(4, 4, 14, 30)
(5, 3, 17, 0)
(5, 5, 16, 55)
GBPUSD
(1, 2, 10, 30)
(1, 3, 10, 30)
(1, 3, 16, 0)
(1, 4, 14, 0)
(1, 4, 14, 40)
(1, 4, 16, 0)
(1, 5, 14, 30)
(1, 5, 14, 35)
(1, 5, 14, 40)
(1, 5, 15, 30)
(1, 5, 15, 35)
(1, 5, 16, 0)
(2, 2, 10, 30)
(2, 4, 14, 30)
(3, 2, 10, 30)
(3, 3, 10, 30)
(3, 4, 10, 30)
(3, 4, 14, 30)
(4, 1, 0, 0)
(5, 5, 14, 30)
USDJPY
(1, 1, 0, 0)
(1, 5, 14, 30)
(1, 5, 14, 35)
(1, 5, 14, 40)
(1, 5, 15, 30)
(1, 5, 15, 35)
(1, 5, 15, 40)
(1, 5, 15, 45)
(1, 5, 16, 0)
(2, 1, 0, 0)
(2, 4, 14, 30)
(2, 5, 15, 30)
(3, 1, 0, 0)
(3, 4, 14, 30)
(4, 1, 0, 0)
(5, 1, 0, 0)
RANDOM

サンプルプログラム

以下のプログラムを実行するにはかなり時間がかかる。私の環境では約1時間かかった。

○以下のプログラムをJupyterにコピー・アンド・ペーストして実行ボタンをクリックする。

import forex_system as fs
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime

def find_date(position, timeframe):
    position = position * timeframe
    minute = position % 60
    hour = int(np.floor((position % 1440) / 60))
    day_of_week = int(np.floor((position % 7200) / 1440) + 1)
    week_of_month = int(np.floor((position % 36000) / 7200) + 1)
    return week_of_month, day_of_week, hour, minute

fs.remove_temp_folder()

timeframe = 5
n = 7200
x = np.empty(n)
y = np.empty(n)
event = np.zeros([n, 5])
plt.figure(figsize=(6, 20))
cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    cnt += 1
    plt.subplot(5, 1, cnt)
    for year in [2012, 2013, 2014, 2015, 2016]:
        start = datetime.strptime(str(year) + '.01.01 00:00',
                                  '%Y.%m.%d %H:%M')
        end = datetime.strptime(str(year) + '.12.31 23:59',
                                '%Y.%m.%d %H:%M')
        ret = fs.i_trange(symbol, timeframe, 0)[start:end]
        mean = np.mean(ret)
        for i in range(5):
            for j in range(5):
                for k in range(24):
                    for l in range(12):
                        x[i*1440+j*288+k*12+l] = i*1440+j*288+k*12+l
                        y[i*1440+j*288+k*12+l] = np.mean(
                                ret[(fs.time_week_of_month(ret.index)==i+1) &
                                    (fs.time_day_of_week(ret.index)==j+1) &
                                    (fs.time_hour(ret.index)==k) &
                                    (fs.time_minute(ret.index)==l*5)]) / mean
                        if y[i*1440+j*288+k*12+l] >= 2:
                            event[i*1440+j*288+k*12+l][cnt-1] += 1
        plt.plot(x, y, label=str(year))
    plt.title('Event and Volatility (' + symbol + ')')
    plt.xlabel('Week of Month')
    plt.ylabel('True Range (Mean=1.0)')
    plt.xlim(0, 7200)
    plt.ylim(0, 13)
    plt.xticks([720, 2160, 3600, 5040, 6480], [1, 2, 3, 4, 5])
    plt.legend(loc='upper right')
    plt.axvline(x=1440, color='black', linestyle=':')
    plt.axvline(x=2880, color='black', linestyle=':')
    plt.axvline(x=4320, color='black', linestyle=':')
    plt.axvline(x=5760, color='black', linestyle=':')
    plt.axhline(y=1.0, color='black', linestyle=':')
    plt.tight_layout()
plt.savefig('event_and_volatility.png', dpi=150)
plt.show()

cnt = 0
for symbol in ['AUDUSD', 'EURUSD', 'GBPUSD', 'USDJPY', 'RANDOM']:
    print(symbol)
    position = np.where(event[0:, cnt]==5)[0]
    size = len(position)
    for i in range(size):
        date = find_date(position[i], timeframe)
        print(date)
    cnt += 1

fs.remove_temp_folder()
(2017/03/02更新)

コメント

非公開コメント